@elisra-devops/docgen-data-provider 1.74.0 → 1.75.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 -8
- package/bin/modules/ResultDataProvider.js +32 -164
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +8 -80
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +29 -233
- package/src/tests/modules/ResultDataProvider.test.ts +10 -96
|
@@ -65,7 +65,7 @@ export default class ResultDataProvider {
|
|
|
65
65
|
* Builds MEWP L2 requirement coverage rows for audit reporting.
|
|
66
66
|
* Rows are one Requirement-TestCase pair; uncovered requirements are emitted with empty test-case columns.
|
|
67
67
|
*/
|
|
68
|
-
getMewpL2CoverageFlatResults(testPlanId: string, projectName: string, selectedSuiteIds: number[] | undefined
|
|
68
|
+
getMewpL2CoverageFlatResults(testPlanId: string, projectName: string, selectedSuiteIds: number[] | undefined): Promise<{
|
|
69
69
|
sheetName: string;
|
|
70
70
|
columnOrder: string[];
|
|
71
71
|
rows: any[];
|
|
@@ -77,6 +77,7 @@ export default class ResultDataProvider {
|
|
|
77
77
|
mapAttachmentsUrl(runResults: any[], project: string): any[];
|
|
78
78
|
private buildMewpCoverageSheetName;
|
|
79
79
|
private createMewpCoverageRow;
|
|
80
|
+
private formatMewpCustomerId;
|
|
80
81
|
private buildMewpCoverageRows;
|
|
81
82
|
private buildMewpTestCaseTitleMap;
|
|
82
83
|
private extractMewpTestCaseId;
|
|
@@ -88,13 +89,6 @@ export default class ResultDataProvider {
|
|
|
88
89
|
private normalizeRequirementStepText;
|
|
89
90
|
private toRequirementKey;
|
|
90
91
|
private fetchMewpL2Requirements;
|
|
91
|
-
private extractMewpQueryHref;
|
|
92
|
-
private fetchMewpL2RequirementsFromQuery;
|
|
93
|
-
private upsertMewpRequirement;
|
|
94
|
-
private hydrateMewpRequirementsFromWorkItems;
|
|
95
|
-
private getMewpWorkItemType;
|
|
96
|
-
private isMewpRequirementType;
|
|
97
|
-
private isMewpTestCaseType;
|
|
98
92
|
private fetchMewpRequirementTypeNames;
|
|
99
93
|
private fetchWorkItemsByIds;
|
|
100
94
|
private extractLinkedTestCaseIdsFromRequirement;
|
|
@@ -283,7 +283,7 @@ class ResultDataProvider {
|
|
|
283
283
|
* Builds MEWP L2 requirement coverage rows for audit reporting.
|
|
284
284
|
* Rows are one Requirement-TestCase pair; uncovered requirements are emitted with empty test-case columns.
|
|
285
285
|
*/
|
|
286
|
-
async getMewpL2CoverageFlatResults(testPlanId, projectName, selectedSuiteIds
|
|
286
|
+
async getMewpL2CoverageFlatResults(testPlanId, projectName, selectedSuiteIds) {
|
|
287
287
|
var _a, _b;
|
|
288
288
|
const defaultPayload = {
|
|
289
289
|
sheetName: `MEWP L2 Coverage - Plan ${testPlanId}`,
|
|
@@ -294,7 +294,7 @@ class ResultDataProvider {
|
|
|
294
294
|
const planName = await this.fetchTestPlanName(testPlanId, projectName);
|
|
295
295
|
const suites = await this.fetchTestSuites(testPlanId, projectName, selectedSuiteIds, true);
|
|
296
296
|
const testData = await this.fetchTestData(suites, projectName, testPlanId, false);
|
|
297
|
-
const requirements = await this.fetchMewpL2Requirements(projectName
|
|
297
|
+
const requirements = await this.fetchMewpL2Requirements(projectName);
|
|
298
298
|
if (requirements.length === 0) {
|
|
299
299
|
return Object.assign(Object.assign({}, defaultPayload), { sheetName: this.buildMewpCoverageSheetName(planName, testPlanId) });
|
|
300
300
|
}
|
|
@@ -395,9 +395,9 @@ class ResultDataProvider {
|
|
|
395
395
|
return `MEWP L2 Coverage - ${suffix}`;
|
|
396
396
|
}
|
|
397
397
|
createMewpCoverageRow(requirement, testCaseId, testCaseTitle, stepSummary) {
|
|
398
|
-
const customerId =
|
|
399
|
-
const customerTitle =
|
|
400
|
-
const responsibility =
|
|
398
|
+
const customerId = this.formatMewpCustomerId(requirement.requirementId);
|
|
399
|
+
const customerTitle = this.toMewpComparableText(requirement.title);
|
|
400
|
+
const responsibility = this.toMewpComparableText(requirement.responsibility);
|
|
401
401
|
const safeTestCaseId = Number.isFinite(testCaseId) && Number(testCaseId) > 0 ? Number(testCaseId) : '';
|
|
402
402
|
return {
|
|
403
403
|
'Customer ID': customerId,
|
|
@@ -410,6 +410,15 @@ class ResultDataProvider {
|
|
|
410
410
|
'Number of not run tests': Number.isFinite(stepSummary === null || stepSummary === void 0 ? void 0 : stepSummary.notRun) ? stepSummary.notRun : 0,
|
|
411
411
|
};
|
|
412
412
|
}
|
|
413
|
+
formatMewpCustomerId(rawValue) {
|
|
414
|
+
const normalized = this.normalizeMewpRequirementCode(this.toMewpComparableText(rawValue));
|
|
415
|
+
if (normalized)
|
|
416
|
+
return normalized;
|
|
417
|
+
const onlyDigits = String(rawValue || '').replace(/\D/g, '');
|
|
418
|
+
if (onlyDigits)
|
|
419
|
+
return `SR${onlyDigits}`;
|
|
420
|
+
return '';
|
|
421
|
+
}
|
|
413
422
|
buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, testCaseTitleMap) {
|
|
414
423
|
var _a;
|
|
415
424
|
const rows = [];
|
|
@@ -603,12 +612,8 @@ class ResultDataProvider {
|
|
|
603
612
|
return '';
|
|
604
613
|
return `SR${digits}`;
|
|
605
614
|
}
|
|
606
|
-
async fetchMewpL2Requirements(projectName
|
|
615
|
+
async fetchMewpL2Requirements(projectName) {
|
|
607
616
|
var _a;
|
|
608
|
-
const queryHref = this.extractMewpQueryHref(linkedQueryRequest);
|
|
609
|
-
if (queryHref) {
|
|
610
|
-
return this.fetchMewpL2RequirementsFromQuery(projectName, queryHref);
|
|
611
|
-
}
|
|
612
617
|
const workItemTypeNames = await this.fetchMewpRequirementTypeNames(projectName);
|
|
613
618
|
if (workItemTypeNames.length === 0) {
|
|
614
619
|
return [];
|
|
@@ -636,165 +641,13 @@ ORDER BY [System.Id]`;
|
|
|
636
641
|
return {
|
|
637
642
|
workItemId: Number((wi === null || wi === void 0 ? void 0 : wi.id) || 0),
|
|
638
643
|
requirementId: this.extractMewpRequirementIdentifier(fields, Number((wi === null || wi === void 0 ? void 0 : wi.id) || 0)),
|
|
639
|
-
title:
|
|
644
|
+
title: this.toMewpComparableText((fields === null || fields === void 0 ? void 0 : fields['System.Title']) || (wi === null || wi === void 0 ? void 0 : wi.title)),
|
|
640
645
|
responsibility: this.deriveMewpResponsibility(fields),
|
|
641
646
|
linkedTestCaseIds: this.extractLinkedTestCaseIdsFromRequirement((wi === null || wi === void 0 ? void 0 : wi.relations) || []),
|
|
642
647
|
};
|
|
643
648
|
});
|
|
644
649
|
return requirements.sort((a, b) => String(a.requirementId).localeCompare(String(b.requirementId)));
|
|
645
650
|
}
|
|
646
|
-
extractMewpQueryHref(linkedQueryRequest) {
|
|
647
|
-
var _a, _b;
|
|
648
|
-
const mode = String((linkedQueryRequest === null || linkedQueryRequest === void 0 ? void 0 : linkedQueryRequest.linkedQueryMode) || '')
|
|
649
|
-
.trim()
|
|
650
|
-
.toLowerCase();
|
|
651
|
-
if (mode !== 'query')
|
|
652
|
-
return '';
|
|
653
|
-
return String(((_b = (_a = linkedQueryRequest === null || linkedQueryRequest === void 0 ? void 0 : linkedQueryRequest.testAssociatedQuery) === null || _a === void 0 ? void 0 : _a.wiql) === null || _b === void 0 ? void 0 : _b.href) || '').trim();
|
|
654
|
-
}
|
|
655
|
-
async fetchMewpL2RequirementsFromQuery(projectName, queryHref) {
|
|
656
|
-
try {
|
|
657
|
-
const ticketsDataProvider = new TicketsDataProvider_1.default(this.orgUrl, this.token);
|
|
658
|
-
const queryResult = await ticketsDataProvider.GetQueryResultsFromWiql(queryHref, true, new Map());
|
|
659
|
-
const requirementTypeNames = await this.fetchMewpRequirementTypeNames(projectName);
|
|
660
|
-
const requirementTypeSet = new Set(requirementTypeNames.map((name) => String(name || '').trim().toLowerCase()));
|
|
661
|
-
const requirementsById = new Map();
|
|
662
|
-
const upsertRequirement = (workItem) => {
|
|
663
|
-
this.upsertMewpRequirement(requirementsById, workItem, requirementTypeSet);
|
|
664
|
-
};
|
|
665
|
-
const linkRequirementToTestCase = (requirementWorkItem, testCaseWorkItem) => {
|
|
666
|
-
const requirementId = Number((requirementWorkItem === null || requirementWorkItem === void 0 ? void 0 : requirementWorkItem.id) || 0);
|
|
667
|
-
const testCaseId = Number((testCaseWorkItem === null || testCaseWorkItem === void 0 ? void 0 : testCaseWorkItem.id) || 0);
|
|
668
|
-
if (!Number.isFinite(requirementId) || requirementId <= 0)
|
|
669
|
-
return;
|
|
670
|
-
if (!Number.isFinite(testCaseId) || testCaseId <= 0)
|
|
671
|
-
return;
|
|
672
|
-
upsertRequirement(requirementWorkItem);
|
|
673
|
-
const requirement = requirementsById.get(requirementId);
|
|
674
|
-
if (!requirement)
|
|
675
|
-
return;
|
|
676
|
-
requirement.linkedTestCaseIds.add(testCaseId);
|
|
677
|
-
};
|
|
678
|
-
if (Array.isArray(queryResult === null || queryResult === void 0 ? void 0 : queryResult.fetchedWorkItems)) {
|
|
679
|
-
for (const workItem of queryResult.fetchedWorkItems) {
|
|
680
|
-
upsertRequirement(workItem);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
if ((queryResult === null || queryResult === void 0 ? void 0 : queryResult.sourceTargetsMap) && typeof queryResult.sourceTargetsMap.entries === 'function') {
|
|
684
|
-
for (const [sourceItem, targets] of queryResult.sourceTargetsMap.entries()) {
|
|
685
|
-
const sourceType = this.getMewpWorkItemType(sourceItem);
|
|
686
|
-
const sourceIsRequirement = this.isMewpRequirementType(sourceType, requirementTypeSet);
|
|
687
|
-
const sourceIsTestCase = this.isMewpTestCaseType(sourceType);
|
|
688
|
-
if (sourceIsRequirement) {
|
|
689
|
-
upsertRequirement(sourceItem);
|
|
690
|
-
}
|
|
691
|
-
const relatedItems = Array.isArray(targets) ? targets : [];
|
|
692
|
-
for (const targetItem of relatedItems) {
|
|
693
|
-
const targetType = this.getMewpWorkItemType(targetItem);
|
|
694
|
-
const targetIsRequirement = this.isMewpRequirementType(targetType, requirementTypeSet);
|
|
695
|
-
const targetIsTestCase = this.isMewpTestCaseType(targetType);
|
|
696
|
-
if (targetIsRequirement) {
|
|
697
|
-
upsertRequirement(targetItem);
|
|
698
|
-
}
|
|
699
|
-
if (sourceIsRequirement && targetIsTestCase) {
|
|
700
|
-
linkRequirementToTestCase(sourceItem, targetItem);
|
|
701
|
-
}
|
|
702
|
-
else if (sourceIsTestCase && targetIsRequirement) {
|
|
703
|
-
linkRequirementToTestCase(targetItem, sourceItem);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
await this.hydrateMewpRequirementsFromWorkItems(projectName, requirementsById);
|
|
709
|
-
return [...requirementsById.values()]
|
|
710
|
-
.map((requirement) => ({
|
|
711
|
-
workItemId: requirement.workItemId,
|
|
712
|
-
requirementId: requirement.requirementId,
|
|
713
|
-
title: requirement.title,
|
|
714
|
-
responsibility: requirement.responsibility,
|
|
715
|
-
linkedTestCaseIds: [...requirement.linkedTestCaseIds].sort((a, b) => a - b),
|
|
716
|
-
}))
|
|
717
|
-
.sort((a, b) => String(a.requirementId).localeCompare(String(b.requirementId)));
|
|
718
|
-
}
|
|
719
|
-
catch (error) {
|
|
720
|
-
logger_1.default.error(`Could not fetch MEWP requirements from query: ${(error === null || error === void 0 ? void 0 : error.message) || error}`);
|
|
721
|
-
return [];
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
upsertMewpRequirement(requirementsById, workItem, requirementTypeSet) {
|
|
725
|
-
const workItemId = Number((workItem === null || workItem === void 0 ? void 0 : workItem.id) || 0);
|
|
726
|
-
if (!Number.isFinite(workItemId) || workItemId <= 0)
|
|
727
|
-
return;
|
|
728
|
-
const fields = (workItem === null || workItem === void 0 ? void 0 : workItem.fields) || {};
|
|
729
|
-
const workItemType = this.getMewpWorkItemType(workItem);
|
|
730
|
-
if (!this.isMewpRequirementType(workItemType, requirementTypeSet))
|
|
731
|
-
return;
|
|
732
|
-
const existing = requirementsById.get(workItemId) || {
|
|
733
|
-
workItemId,
|
|
734
|
-
requirementId: String(workItemId),
|
|
735
|
-
title: '',
|
|
736
|
-
responsibility: '',
|
|
737
|
-
linkedTestCaseIds: new Set(),
|
|
738
|
-
};
|
|
739
|
-
const extractedRequirementId = this.extractMewpRequirementIdentifier(fields, workItemId);
|
|
740
|
-
const extractedTitle = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['System.Title']);
|
|
741
|
-
const extractedResponsibility = this.deriveMewpResponsibility(fields);
|
|
742
|
-
existing.requirementId = extractedRequirementId || existing.requirementId || String(workItemId);
|
|
743
|
-
if (extractedTitle) {
|
|
744
|
-
existing.title = extractedTitle;
|
|
745
|
-
}
|
|
746
|
-
if (extractedResponsibility) {
|
|
747
|
-
existing.responsibility = extractedResponsibility;
|
|
748
|
-
}
|
|
749
|
-
requirementsById.set(workItemId, existing);
|
|
750
|
-
}
|
|
751
|
-
async hydrateMewpRequirementsFromWorkItems(projectName, requirementsById) {
|
|
752
|
-
const requirementIds = [...requirementsById.keys()];
|
|
753
|
-
if (requirementIds.length === 0)
|
|
754
|
-
return;
|
|
755
|
-
const fetchedRequirements = await this.fetchWorkItemsByIds(projectName, requirementIds, true);
|
|
756
|
-
for (const requirementWorkItem of fetchedRequirements) {
|
|
757
|
-
const workItemId = Number((requirementWorkItem === null || requirementWorkItem === void 0 ? void 0 : requirementWorkItem.id) || 0);
|
|
758
|
-
if (!Number.isFinite(workItemId) || workItemId <= 0)
|
|
759
|
-
continue;
|
|
760
|
-
const current = requirementsById.get(workItemId);
|
|
761
|
-
if (!current)
|
|
762
|
-
continue;
|
|
763
|
-
const fields = (requirementWorkItem === null || requirementWorkItem === void 0 ? void 0 : requirementWorkItem.fields) || {};
|
|
764
|
-
const requirementId = this.extractMewpRequirementIdentifier(fields, workItemId);
|
|
765
|
-
const title = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['System.Title']);
|
|
766
|
-
const responsibility = this.deriveMewpResponsibility(fields);
|
|
767
|
-
const linkedTestCaseIds = this.extractLinkedTestCaseIdsFromRequirement((requirementWorkItem === null || requirementWorkItem === void 0 ? void 0 : requirementWorkItem.relations) || []);
|
|
768
|
-
current.requirementId = requirementId || current.requirementId || String(workItemId);
|
|
769
|
-
if (title) {
|
|
770
|
-
current.title = title;
|
|
771
|
-
}
|
|
772
|
-
if (responsibility) {
|
|
773
|
-
current.responsibility = responsibility;
|
|
774
|
-
}
|
|
775
|
-
linkedTestCaseIds.forEach((testCaseId) => current.linkedTestCaseIds.add(testCaseId));
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
getMewpWorkItemType(workItem) {
|
|
779
|
-
var _a;
|
|
780
|
-
return this.toMewpComparableText((_a = workItem === null || workItem === void 0 ? void 0 : workItem.fields) === null || _a === void 0 ? void 0 : _a['System.WorkItemType']);
|
|
781
|
-
}
|
|
782
|
-
isMewpRequirementType(workItemType, requirementTypeSet) {
|
|
783
|
-
const normalized = String(workItemType || '')
|
|
784
|
-
.trim()
|
|
785
|
-
.toLowerCase();
|
|
786
|
-
if (!normalized)
|
|
787
|
-
return false;
|
|
788
|
-
if (requirementTypeSet.has(normalized))
|
|
789
|
-
return true;
|
|
790
|
-
return normalized.includes('requirement') || normalized === 'epic';
|
|
791
|
-
}
|
|
792
|
-
isMewpTestCaseType(workItemType) {
|
|
793
|
-
const normalized = String(workItemType || '')
|
|
794
|
-
.trim()
|
|
795
|
-
.toLowerCase();
|
|
796
|
-
return normalized === 'test case' || normalized === 'testcase';
|
|
797
|
-
}
|
|
798
651
|
async fetchMewpRequirementTypeNames(projectName) {
|
|
799
652
|
try {
|
|
800
653
|
const url = `${this.orgUrl}${projectName}/_apis/wit/workitemtypes?api-version=7.1-preview.2`;
|
|
@@ -890,9 +743,21 @@ ORDER BY [System.Id]`;
|
|
|
890
743
|
const titleCode = this.normalizeMewpRequirementCode(title);
|
|
891
744
|
if (titleCode)
|
|
892
745
|
return titleCode;
|
|
893
|
-
return
|
|
746
|
+
return fallbackWorkItemId ? `SR${fallbackWorkItemId}` : '';
|
|
894
747
|
}
|
|
895
748
|
deriveMewpResponsibility(fields) {
|
|
749
|
+
const explicitSapWbs = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['Custom.SAPWBS']);
|
|
750
|
+
const fromExplicitSapWbs = this.resolveMewpResponsibility(explicitSapWbs);
|
|
751
|
+
if (fromExplicitSapWbs)
|
|
752
|
+
return fromExplicitSapWbs;
|
|
753
|
+
if (explicitSapWbs)
|
|
754
|
+
return explicitSapWbs;
|
|
755
|
+
const explicitSapWbsByLabel = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['SAPWBS']);
|
|
756
|
+
const fromExplicitLabel = this.resolveMewpResponsibility(explicitSapWbsByLabel);
|
|
757
|
+
if (fromExplicitLabel)
|
|
758
|
+
return fromExplicitLabel;
|
|
759
|
+
if (explicitSapWbsByLabel)
|
|
760
|
+
return explicitSapWbsByLabel;
|
|
896
761
|
const areaPath = this.toMewpComparableText(fields === null || fields === void 0 ? void 0 : fields['System.AreaPath']);
|
|
897
762
|
const fromAreaPath = this.resolveMewpResponsibility(areaPath);
|
|
898
763
|
if (fromAreaPath)
|
|
@@ -945,6 +810,9 @@ ORDER BY [System.Id]`;
|
|
|
945
810
|
const uniqueName = value.uniqueName;
|
|
946
811
|
if (uniqueName)
|
|
947
812
|
return String(uniqueName).trim();
|
|
813
|
+
const objectValue = value.value;
|
|
814
|
+
if (objectValue !== undefined && objectValue !== null)
|
|
815
|
+
return String(objectValue).trim();
|
|
948
816
|
}
|
|
949
817
|
return String(value).trim();
|
|
950
818
|
}
|