@elisra-devops/docgen-data-provider 1.92.0 → 1.93.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 +8 -1
- package/bin/modules/ResultDataProvider.js +123 -23
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +155 -25
- package/src/tests/modules/ResultDataProvider.test.ts +1 -1
|
@@ -23,6 +23,9 @@ import type { MewpCoverageFlatPayload, MewpExternalFilesValidationResponse, Mewp
|
|
|
23
23
|
* Instantiate the class with the organization URL and token, and use the provided methods to fetch and process test data.
|
|
24
24
|
*/
|
|
25
25
|
export default class ResultDataProvider {
|
|
26
|
+
private static readonly MEWP_INTERNAL_VALIDATION_TRACE_TAG;
|
|
27
|
+
private static readonly MEWP_INTERNAL_VALIDATION_DIAGNOSTICS_TAG;
|
|
28
|
+
private static readonly MEWP_INTERNAL_VALIDATION_SUMMARY_TAG;
|
|
26
29
|
private static readonly MEWP_L2_COVERAGE_COLUMNS;
|
|
27
30
|
private static readonly INTERNAL_VALIDATION_COLUMNS;
|
|
28
31
|
orgUrl: string;
|
|
@@ -70,7 +73,9 @@ export default class ResultDataProvider {
|
|
|
70
73
|
* Rows are one Requirement-TestCase pair; uncovered requirements are emitted with empty test-case columns.
|
|
71
74
|
*/
|
|
72
75
|
getMewpL2CoverageFlatResults(testPlanId: string, projectName: string, selectedSuiteIds: number[] | undefined, linkedQueryRequest?: any, options?: MewpCoverageRequestOptions): Promise<MewpCoverageFlatPayload>;
|
|
73
|
-
getMewpInternalValidationFlatResults(testPlanId: string, projectName: string, selectedSuiteIds: number[] | undefined, linkedQueryRequest?: any
|
|
76
|
+
getMewpInternalValidationFlatResults(testPlanId: string, projectName: string, selectedSuiteIds: number[] | undefined, linkedQueryRequest?: any, options?: {
|
|
77
|
+
debugMode?: boolean;
|
|
78
|
+
}): Promise<MewpInternalValidationFlatPayload>;
|
|
74
79
|
validateMewpExternalFiles(options: {
|
|
75
80
|
externalBugsFile?: MewpExternalFileRef | null;
|
|
76
81
|
externalL3L4File?: MewpExternalFileRef | null;
|
|
@@ -82,6 +87,8 @@ export default class ResultDataProvider {
|
|
|
82
87
|
mapAttachmentsUrl(runResults: any[], project: string): any[];
|
|
83
88
|
private buildMewpCoverageSheetName;
|
|
84
89
|
private buildInternalValidationSheetName;
|
|
90
|
+
private formatLogValue;
|
|
91
|
+
private buildTaggedLogMessage;
|
|
85
92
|
private createMewpCoverageRow;
|
|
86
93
|
private createEmptyMewpCoverageBugCell;
|
|
87
94
|
private createEmptyMewpCoverageL3L4Cell;
|
|
@@ -475,7 +475,7 @@ class ResultDataProvider {
|
|
|
475
475
|
return defaultPayload;
|
|
476
476
|
}
|
|
477
477
|
}
|
|
478
|
-
async getMewpInternalValidationFlatResults(testPlanId, projectName, selectedSuiteIds, linkedQueryRequest) {
|
|
478
|
+
async getMewpInternalValidationFlatResults(testPlanId, projectName, selectedSuiteIds, linkedQueryRequest, options) {
|
|
479
479
|
var _a, _b;
|
|
480
480
|
const defaultPayload = {
|
|
481
481
|
sheetName: `MEWP Internal Validation - Plan ${testPlanId}`,
|
|
@@ -546,8 +546,16 @@ class ResultDataProvider {
|
|
|
546
546
|
testCasesWithoutMentionedCustomerIds: 0,
|
|
547
547
|
failingRows: 0,
|
|
548
548
|
};
|
|
549
|
+
const traceInternalValidation = (options === null || options === void 0 ? void 0 : options.debugMode) === true;
|
|
550
|
+
if (traceInternalValidation) {
|
|
551
|
+
logger_1.default.info(this.buildTaggedLogMessage(ResultDataProvider.MEWP_INTERNAL_VALIDATION_TRACE_TAG, {
|
|
552
|
+
mode: 'enabled',
|
|
553
|
+
source: 'ui-debug-mode',
|
|
554
|
+
}));
|
|
555
|
+
}
|
|
549
556
|
for (const testCaseId of [...allTestCaseIds].sort((a, b) => a - b)) {
|
|
550
557
|
diagnostics.totalTestCases += 1;
|
|
558
|
+
const traceCurrentTestCase = traceInternalValidation;
|
|
551
559
|
const stepsXml = stepsXmlByTestCase.get(testCaseId) || '';
|
|
552
560
|
const parsedSteps = stepsXml && String(stepsXml).trim() !== ''
|
|
553
561
|
? await this.testStepParserHelper.parseTestSteps(stepsXml, new Map())
|
|
@@ -593,6 +601,19 @@ class ResultDataProvider {
|
|
|
593
601
|
mentionedCodesByBase.set(baseKey, new Set());
|
|
594
602
|
mentionedCodesByBase.get(baseKey).add(code);
|
|
595
603
|
}
|
|
604
|
+
if (traceCurrentTestCase) {
|
|
605
|
+
logger_1.default.debug(this.buildTaggedLogMessage(ResultDataProvider.MEWP_INTERNAL_VALIDATION_TRACE_TAG, {
|
|
606
|
+
event: 'test-case-start',
|
|
607
|
+
tc: testCaseId,
|
|
608
|
+
parsedSteps: executableSteps.length,
|
|
609
|
+
stepsWithMentions: mentionEntries.length,
|
|
610
|
+
mentionedCodes: [...mentionedL2Only].sort((a, b) => this.compareMewpRequirementCodes(a, b)).join('; ') ||
|
|
611
|
+
'<none>',
|
|
612
|
+
linkedCodesInTestCase: [...linkedFullCodes]
|
|
613
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a, b))
|
|
614
|
+
.join('; ') || '<none>',
|
|
615
|
+
}));
|
|
616
|
+
}
|
|
596
617
|
// Direction A logic:
|
|
597
618
|
// 1) Base mention ("SR0054") is parent-level and considered covered only when
|
|
598
619
|
// the whole family is covered across scoped test cases:
|
|
@@ -608,38 +629,88 @@ class ResultDataProvider {
|
|
|
608
629
|
const mentionedSpecificMembers = mentionedCodesList.filter((code) => /-\d+$/.test(code));
|
|
609
630
|
if (familyCodes === null || familyCodes === void 0 ? void 0 : familyCodes.size) {
|
|
610
631
|
const familyLinkedCodes = linkedFamilyCodesAcrossTestCases.get(baseKey) || new Set();
|
|
632
|
+
const normalizedFamilyMembers = [...familyCodes]
|
|
633
|
+
.map((code) => this.normalizeMewpRequirementCodeWithSuffix(code))
|
|
634
|
+
.filter((code) => !!code);
|
|
635
|
+
const specificFamilyMembers = normalizedFamilyMembers.filter((code) => /-\d+$/.test(code));
|
|
636
|
+
const requiredFamilyMembers = specificFamilyMembers.length > 0 ? specificFamilyMembers : normalizedFamilyMembers;
|
|
611
637
|
// Base mention ("SR0054") requires full family coverage across selected test cases.
|
|
612
638
|
if (hasBaseMention) {
|
|
613
|
-
const
|
|
614
|
-
.map((code) => this.normalizeMewpRequirementCodeWithSuffix(code))
|
|
615
|
-
.filter((code) => !!code);
|
|
616
|
-
const specificFamilyMembers = normalizedFamilyMembers.filter((code) => /-\d+$/.test(code));
|
|
617
|
-
const requiredFamilyMembers = specificFamilyMembers.length > 0 ? specificFamilyMembers : normalizedFamilyMembers;
|
|
639
|
+
const missingRequiredFamilyMembers = requiredFamilyMembers.filter((memberCode) => !familyLinkedCodes.has(memberCode));
|
|
618
640
|
const isWholeFamilyCovered = requiredFamilyMembers.every((memberCode) => familyLinkedCodes.has(memberCode));
|
|
619
641
|
if (!isWholeFamilyCovered) {
|
|
620
642
|
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
621
643
|
}
|
|
644
|
+
if (traceCurrentTestCase) {
|
|
645
|
+
logger_1.default.debug(this.buildTaggedLogMessage(ResultDataProvider.MEWP_INTERNAL_VALIDATION_TRACE_TAG, {
|
|
646
|
+
event: 'base-family-coverage',
|
|
647
|
+
tc: testCaseId,
|
|
648
|
+
base: baseKey,
|
|
649
|
+
baseMention: true,
|
|
650
|
+
requiredFamily: requiredFamilyMembers
|
|
651
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a, b))
|
|
652
|
+
.join('; ') || '<none>',
|
|
653
|
+
linkedAcrossScope: [...familyLinkedCodes]
|
|
654
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a, b))
|
|
655
|
+
.join('; ') || '<none>',
|
|
656
|
+
missingRequired: missingRequiredFamilyMembers
|
|
657
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a, b))
|
|
658
|
+
.join('; ') || '<none>',
|
|
659
|
+
covered: isWholeFamilyCovered,
|
|
660
|
+
}));
|
|
661
|
+
}
|
|
622
662
|
}
|
|
623
663
|
// Specific mention ("SR0054-1") validates as exact-match only across scoped test cases.
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
664
|
+
const missingSpecificMembers = mentionedSpecificMembers.filter((code) => !familyLinkedCodes.has(code));
|
|
665
|
+
for (const code of missingSpecificMembers) {
|
|
666
|
+
missingSpecificMentionedNoFamily.add(code);
|
|
667
|
+
}
|
|
668
|
+
if (traceCurrentTestCase && mentionedSpecificMembers.length > 0) {
|
|
669
|
+
logger_1.default.debug(this.buildTaggedLogMessage(ResultDataProvider.MEWP_INTERNAL_VALIDATION_TRACE_TAG, {
|
|
670
|
+
event: 'specific-members-check',
|
|
671
|
+
tc: testCaseId,
|
|
672
|
+
base: baseKey,
|
|
673
|
+
specificMentioned: mentionedSpecificMembers
|
|
674
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a, b))
|
|
675
|
+
.join('; ') || '<none>',
|
|
676
|
+
specificMissing: missingSpecificMembers
|
|
677
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a, b))
|
|
678
|
+
.join('; ') || '<none>',
|
|
679
|
+
}));
|
|
628
680
|
}
|
|
629
681
|
continue;
|
|
630
682
|
}
|
|
631
683
|
// Fallback path when family data is unavailable for this base key.
|
|
684
|
+
const fallbackMissingSpecific = [];
|
|
685
|
+
let fallbackMissingBase = false;
|
|
632
686
|
for (const code of mentionedCodes) {
|
|
633
687
|
const hasSpecificSuffix = /-\d+$/.test(code);
|
|
634
688
|
if (hasSpecificSuffix) {
|
|
635
689
|
if (!linkedFullCodesAcrossTestCases.has(code)) {
|
|
636
690
|
missingSpecificMentionedNoFamily.add(code);
|
|
691
|
+
fallbackMissingSpecific.push(code);
|
|
637
692
|
}
|
|
638
693
|
}
|
|
639
694
|
else if (!linkedBaseKeysAcrossTestCases.has(baseKey)) {
|
|
640
695
|
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
696
|
+
fallbackMissingBase = true;
|
|
641
697
|
}
|
|
642
698
|
}
|
|
699
|
+
if (traceCurrentTestCase) {
|
|
700
|
+
logger_1.default.debug(this.buildTaggedLogMessage(ResultDataProvider.MEWP_INTERNAL_VALIDATION_TRACE_TAG, {
|
|
701
|
+
event: 'fallback-path',
|
|
702
|
+
tc: testCaseId,
|
|
703
|
+
base: baseKey,
|
|
704
|
+
fallbackUsed: true,
|
|
705
|
+
mentioned: mentionedCodesList
|
|
706
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a, b))
|
|
707
|
+
.join('; ') || '<none>',
|
|
708
|
+
missingSpecific: fallbackMissingSpecific
|
|
709
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a, b))
|
|
710
|
+
.join('; ') || '<none>',
|
|
711
|
+
missingBase: fallbackMissingBase,
|
|
712
|
+
}));
|
|
713
|
+
}
|
|
643
714
|
}
|
|
644
715
|
// Direction B is family-based: if any member of a family is mentioned in Expected Result,
|
|
645
716
|
// linked members of that same family are not considered "linked but not mentioned".
|
|
@@ -679,6 +750,14 @@ class ResultDataProvider {
|
|
|
679
750
|
const stepRef = mentionedBaseFirstStep.get(baseKey) || 'Step ?';
|
|
680
751
|
appendMentionedButNotLinked(baseKey, stepRef);
|
|
681
752
|
}
|
|
753
|
+
if (traceCurrentTestCase) {
|
|
754
|
+
logger_1.default.debug(this.buildTaggedLogMessage(ResultDataProvider.MEWP_INTERNAL_VALIDATION_TRACE_TAG, {
|
|
755
|
+
event: 'direction-a-summary',
|
|
756
|
+
tc: testCaseId,
|
|
757
|
+
missingSpecific: sortedMissingSpecificMentionedNoFamily.join('; ') || '<none>',
|
|
758
|
+
missingBase: sortedMissingBaseWhenFamilyUncovered.join('; ') || '<none>',
|
|
759
|
+
}));
|
|
760
|
+
}
|
|
682
761
|
const sortedExtraLinked = [...new Set(extraLinked)]
|
|
683
762
|
.map((code) => this.normalizeMewpRequirementCodeWithSuffix(code))
|
|
684
763
|
.filter((code) => !!code)
|
|
@@ -713,13 +792,18 @@ class ResultDataProvider {
|
|
|
713
792
|
const validationStatus = mentionedButNotLinked || linkedButNotMentioned ? 'Fail' : 'Pass';
|
|
714
793
|
if (validationStatus === 'Fail')
|
|
715
794
|
diagnostics.failingRows += 1;
|
|
716
|
-
logger_1.default.debug(
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
795
|
+
logger_1.default.debug(this.buildTaggedLogMessage(ResultDataProvider.MEWP_INTERNAL_VALIDATION_DIAGNOSTICS_TAG, {
|
|
796
|
+
testCaseId,
|
|
797
|
+
parsedSteps: executableSteps.length,
|
|
798
|
+
stepsWithMentions: mentionEntries.length,
|
|
799
|
+
customerIdsFound: mentionedL2Only.size,
|
|
800
|
+
linkedRequirements: linkedFullCodes.size,
|
|
801
|
+
mentionedButNotLinked: sortedMissingSpecificMentionedNoFamily.length +
|
|
802
|
+
sortedMissingBaseWhenFamilyUncovered.length,
|
|
803
|
+
linkedButNotMentioned: sortedExtraLinked.length,
|
|
804
|
+
status: validationStatus,
|
|
805
|
+
customerIdSample: [...mentionedL2Only].slice(0, 5).join(', '),
|
|
806
|
+
}));
|
|
723
807
|
rows.push({
|
|
724
808
|
'Test Case ID': testCaseId,
|
|
725
809
|
'Test Case Title': String(testCaseTitleMap.get(testCaseId) || '').trim(),
|
|
@@ -728,11 +812,14 @@ class ResultDataProvider {
|
|
|
728
812
|
'Validation Status': validationStatus,
|
|
729
813
|
});
|
|
730
814
|
}
|
|
731
|
-
logger_1.default.info(
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
815
|
+
logger_1.default.info(this.buildTaggedLogMessage(ResultDataProvider.MEWP_INTERNAL_VALIDATION_SUMMARY_TAG, {
|
|
816
|
+
testCases: diagnostics.totalTestCases,
|
|
817
|
+
parsedSteps: diagnostics.totalParsedSteps,
|
|
818
|
+
stepsWithMentions: diagnostics.totalStepsWithMentions,
|
|
819
|
+
totalCustomerIdsFound: diagnostics.totalMentionedCustomerIds,
|
|
820
|
+
testCasesWithoutCustomerIds: diagnostics.testCasesWithoutMentionedCustomerIds,
|
|
821
|
+
failingRows: diagnostics.failingRows,
|
|
822
|
+
}));
|
|
736
823
|
return {
|
|
737
824
|
sheetName: this.buildInternalValidationSheetName(planName, testPlanId),
|
|
738
825
|
columnOrder: [...ResultDataProvider.INTERNAL_VALIDATION_COLUMNS],
|
|
@@ -821,6 +908,16 @@ class ResultDataProvider {
|
|
|
821
908
|
const suffix = String(planName || '').trim() || `Plan ${testPlanId}`;
|
|
822
909
|
return `MEWP Internal Validation - ${suffix}`;
|
|
823
910
|
}
|
|
911
|
+
formatLogValue(value) {
|
|
912
|
+
if (value === null || value === undefined)
|
|
913
|
+
return '<none>';
|
|
914
|
+
const asText = String(value).trim();
|
|
915
|
+
return asText !== '' ? asText : '<none>';
|
|
916
|
+
}
|
|
917
|
+
buildTaggedLogMessage(tag, fields) {
|
|
918
|
+
const sections = Object.entries(fields).map(([key, value]) => `${key}=${this.formatLogValue(value)}`);
|
|
919
|
+
return `${tag} ${sections.join(' | ')}`;
|
|
920
|
+
}
|
|
824
921
|
createMewpCoverageRow(requirement, runStatus, bug, linkedL3L4) {
|
|
825
922
|
const l2ReqIdNumeric = Number((requirement === null || requirement === void 0 ? void 0 : requirement.workItemId) || 0);
|
|
826
923
|
const l2ReqId = l2ReqIdNumeric > 0 ? String(l2ReqIdNumeric) : '';
|
|
@@ -2221,7 +2318,7 @@ class ResultDataProvider {
|
|
|
2221
2318
|
// Direction B display is family-level when multiple members exist.
|
|
2222
2319
|
return baseKey;
|
|
2223
2320
|
})
|
|
2224
|
-
.join('
|
|
2321
|
+
.join('; ');
|
|
2225
2322
|
}
|
|
2226
2323
|
toMewpComparableText(value) {
|
|
2227
2324
|
if (value === null || value === undefined)
|
|
@@ -4200,6 +4297,9 @@ class ResultDataProvider {
|
|
|
4200
4297
|
return customFields;
|
|
4201
4298
|
}
|
|
4202
4299
|
}
|
|
4300
|
+
ResultDataProvider.MEWP_INTERNAL_VALIDATION_TRACE_TAG = '[MEWP][InternalValidation][Trace]';
|
|
4301
|
+
ResultDataProvider.MEWP_INTERNAL_VALIDATION_DIAGNOSTICS_TAG = '[MEWP][InternalValidation][Diagnostics]';
|
|
4302
|
+
ResultDataProvider.MEWP_INTERNAL_VALIDATION_SUMMARY_TAG = '[MEWP][InternalValidation][Summary]';
|
|
4203
4303
|
ResultDataProvider.MEWP_L2_COVERAGE_COLUMNS = [
|
|
4204
4304
|
'L2 REQ ID',
|
|
4205
4305
|
'L2 REQ Title',
|