@elisra-devops/docgen-data-provider 1.84.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 +2 -0
- package/bin/modules/ResultDataProvider.js +146 -19
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +117 -0
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +162 -16
- package/src/tests/modules/ResultDataProvider.test.ts +147 -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;
|
|
@@ -134,6 +135,7 @@ export default class ResultDataProvider {
|
|
|
134
135
|
private extractLinkedWorkItemIdsFromRelations;
|
|
135
136
|
private extractMewpRequirementIdentifier;
|
|
136
137
|
private deriveMewpResponsibility;
|
|
138
|
+
private deriveMewpTestCaseResponsibility;
|
|
137
139
|
private deriveMewpSubSystem;
|
|
138
140
|
private resolveBugResponsibility;
|
|
139
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() !== '';
|
|
@@ -813,7 +814,7 @@ class ResultDataProvider {
|
|
|
813
814
|
return String((a === null || a === void 0 ? void 0 : a.l4Id) || '').localeCompare(String((b === null || b === void 0 ? void 0 : b.l4Id) || ''));
|
|
814
815
|
});
|
|
815
816
|
}
|
|
816
|
-
buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2) {
|
|
817
|
+
buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2, testCaseResponsibilityById) {
|
|
817
818
|
var _a;
|
|
818
819
|
const rows = [];
|
|
819
820
|
const linkedByRequirement = this.invertBaseRequirementLinks(linkedRequirementsByTestCase);
|
|
@@ -847,7 +848,7 @@ class ResultDataProvider {
|
|
|
847
848
|
const bugId = Number((bug === null || bug === void 0 ? void 0 : bug.id) || 0);
|
|
848
849
|
if (!Number.isFinite(bugId) || bugId <= 0)
|
|
849
850
|
continue;
|
|
850
|
-
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)) || '')) }));
|
|
851
852
|
}
|
|
852
853
|
}
|
|
853
854
|
}
|
|
@@ -874,18 +875,114 @@ class ResultDataProvider {
|
|
|
874
875
|
}
|
|
875
876
|
return rows;
|
|
876
877
|
}
|
|
877
|
-
resolveCoverageBugResponsibility(rawResponsibility, requirement) {
|
|
878
|
-
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);
|
|
879
891
|
if (direct && direct.toLowerCase() !== 'unknown')
|
|
880
892
|
return direct;
|
|
881
|
-
const
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
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;
|
|
889
986
|
}
|
|
890
987
|
resolveMewpL2RunStatus(input) {
|
|
891
988
|
if (((input === null || input === void 0 ? void 0 : input.failed) || 0) > 0)
|
|
@@ -1998,11 +2095,42 @@ class ResultDataProvider {
|
|
|
1998
2095
|
return fromExplicitLabel;
|
|
1999
2096
|
if (explicitSapWbsByLabel)
|
|
2000
2097
|
return explicitSapWbsByLabel;
|
|
2001
|
-
const
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
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'];
|
|
2006
2134
|
for (const [key, value] of Object.entries(fields || {})) {
|
|
2007
2135
|
const normalizedKey = String(key || '').toLowerCase();
|
|
2008
2136
|
if (!keyHints.some((hint) => normalizedKey.includes(hint)))
|
|
@@ -2404,7 +2532,6 @@ class ResultDataProvider {
|
|
|
2404
2532
|
logger_1.default.warn(`Invalid run result ${runId} or result ${resultId}`);
|
|
2405
2533
|
return null;
|
|
2406
2534
|
}
|
|
2407
|
-
logger_1.default.warn(`Current Test point for Test case ${point.testCaseId} is in Active state`);
|
|
2408
2535
|
const url = `${this.orgUrl}${projectName}/_apis/wit/workItems/${point.testCaseId}?$expand=all`;
|
|
2409
2536
|
const testCaseData = await tfs_1.TFSServices.getItemContent(url, this.token);
|
|
2410
2537
|
const newResultData = {
|