@elisra-devops/docgen-data-provider 1.85.0 → 1.87.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 +1 -0
- package/bin/modules/ResultDataProvider.js +98 -29
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +285 -1
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +105 -27
- package/src/tests/modules/ResultDataProvider.test.ts +330 -1
|
@@ -142,6 +142,7 @@ export default class ResultDataProvider {
|
|
|
142
142
|
private isExcludedL3L4BySapWbs;
|
|
143
143
|
private normalizeMewpRequirementCode;
|
|
144
144
|
private normalizeMewpRequirementCodeWithSuffix;
|
|
145
|
+
private formatRequirementCodesGroupedByFamily;
|
|
145
146
|
private toMewpComparableText;
|
|
146
147
|
private fetchTestPlanName;
|
|
147
148
|
/**
|
|
@@ -558,34 +558,73 @@ class ResultDataProvider {
|
|
|
558
558
|
diagnostics.testCasesWithoutMentionedCustomerIds += 1;
|
|
559
559
|
}
|
|
560
560
|
const mentionedBaseKeys = new Set([...mentionedL2Only].map((code) => this.toRequirementKey(code)).filter((code) => !!code));
|
|
561
|
-
const expectedFamilyCodes = new Set();
|
|
562
|
-
for (const baseKey of mentionedBaseKeys) {
|
|
563
|
-
const familyCodes = requirementFamilies.get(baseKey);
|
|
564
|
-
if (familyCodes === null || familyCodes === void 0 ? void 0 : familyCodes.size) {
|
|
565
|
-
familyCodes.forEach((code) => expectedFamilyCodes.add(code));
|
|
566
|
-
}
|
|
567
|
-
else {
|
|
568
|
-
for (const code of mentionedL2Only) {
|
|
569
|
-
if (this.toRequirementKey(code) === baseKey)
|
|
570
|
-
expectedFamilyCodes.add(code);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
561
|
const linkedFullCodesRaw = ((_c = linkedRequirementsByTestCase.get(testCaseId)) === null || _c === void 0 ? void 0 : _c.fullCodes) || new Set();
|
|
575
562
|
const linkedFullCodes = (scopedRequirementKeys === null || scopedRequirementKeys === void 0 ? void 0 : scopedRequirementKeys.size) && linkedFullCodesRaw.size > 0
|
|
576
563
|
? new Set([...linkedFullCodesRaw].filter((code) => scopedRequirementKeys.has(this.toRequirementKey(code))))
|
|
577
564
|
: linkedFullCodesRaw;
|
|
578
565
|
const linkedBaseKeys = new Set([...linkedFullCodes].map((code) => this.toRequirementKey(code)).filter((code) => !!code));
|
|
579
|
-
const
|
|
566
|
+
const mentionedCodesByBase = new Map();
|
|
567
|
+
for (const code of mentionedL2Only) {
|
|
580
568
|
const baseKey = this.toRequirementKey(code);
|
|
581
569
|
if (!baseKey)
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
570
|
+
continue;
|
|
571
|
+
if (!mentionedCodesByBase.has(baseKey))
|
|
572
|
+
mentionedCodesByBase.set(baseKey, new Set());
|
|
573
|
+
mentionedCodesByBase.get(baseKey).add(code);
|
|
574
|
+
}
|
|
575
|
+
// Context-based direction A logic:
|
|
576
|
+
// 1) If no member of family is linked -> report only base SR (Step X: SR0054).
|
|
577
|
+
// 2) If family is partially linked -> report only specific missing members.
|
|
578
|
+
// 3) If family fully linked -> report nothing for that family.
|
|
579
|
+
const missingBaseWhenFamilyUncovered = new Set();
|
|
580
|
+
const missingSpecificMentionedNoFamily = new Set();
|
|
581
|
+
const missingFamilyMembers = new Set();
|
|
582
|
+
for (const [baseKey, mentionedCodes] of mentionedCodesByBase.entries()) {
|
|
583
|
+
const familyCodes = requirementFamilies.get(baseKey);
|
|
584
|
+
const mentionedCodesList = [...mentionedCodes];
|
|
585
|
+
const hasBaseMention = mentionedCodesList.some((code) => !/-\d+$/.test(code));
|
|
586
|
+
const mentionedSpecificMembers = mentionedCodesList.filter((code) => /-\d+$/.test(code));
|
|
587
|
+
if (familyCodes === null || familyCodes === void 0 ? void 0 : familyCodes.size) {
|
|
588
|
+
// Base mention ("SR0054") validates against child coverage when children exist.
|
|
589
|
+
// If no child variants exist, fallback to the single standalone requirement code.
|
|
590
|
+
if (hasBaseMention) {
|
|
591
|
+
const familyCodesList = [...familyCodes];
|
|
592
|
+
const childFamilyCodes = familyCodesList.filter((code) => /-\d+$/.test(code));
|
|
593
|
+
const targetFamilyCodes = childFamilyCodes.length > 0 ? childFamilyCodes : familyCodesList;
|
|
594
|
+
const missingInTargetFamily = targetFamilyCodes.filter((code) => !linkedFullCodes.has(code));
|
|
595
|
+
if (missingInTargetFamily.length > 0) {
|
|
596
|
+
const hasAnyLinkedInFamily = familyCodesList.some((code) => linkedFullCodes.has(code));
|
|
597
|
+
if (!hasAnyLinkedInFamily) {
|
|
598
|
+
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
for (const code of missingInTargetFamily) {
|
|
602
|
+
missingFamilyMembers.add(code);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
// Specific mention ("SR0054-1") validates as exact-match only.
|
|
609
|
+
for (const code of mentionedSpecificMembers) {
|
|
610
|
+
if (!linkedFullCodes.has(code)) {
|
|
611
|
+
missingSpecificMentionedNoFamily.add(code);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
// Fallback path when family data is unavailable for this base key.
|
|
617
|
+
for (const code of mentionedCodes) {
|
|
618
|
+
const hasSpecificSuffix = /-\d+$/.test(code);
|
|
619
|
+
if (hasSpecificSuffix) {
|
|
620
|
+
if (!linkedFullCodes.has(code))
|
|
621
|
+
missingSpecificMentionedNoFamily.add(code);
|
|
622
|
+
}
|
|
623
|
+
else if (!linkedBaseKeys.has(baseKey)) {
|
|
624
|
+
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
589
628
|
// Direction B is family-based: if any member of a family is mentioned in Expected Result,
|
|
590
629
|
// linked members of that same family are not considered "linked but not mentioned".
|
|
591
630
|
const extraLinked = [...linkedFullCodes].filter((code) => {
|
|
@@ -605,13 +644,18 @@ class ResultDataProvider {
|
|
|
605
644
|
}
|
|
606
645
|
mentionedButNotLinkedByStep.get(normalizedStepRef).add(normalizedRequirementId);
|
|
607
646
|
};
|
|
608
|
-
const
|
|
609
|
-
const
|
|
610
|
-
|
|
647
|
+
const sortedMissingSpecificMentionedNoFamily = [...missingSpecificMentionedNoFamily].sort((a, b) => a.localeCompare(b));
|
|
648
|
+
const sortedMissingBaseWhenFamilyUncovered = [...missingBaseWhenFamilyUncovered].sort((a, b) => a.localeCompare(b));
|
|
649
|
+
const sortedMissingFamilyMembers = [...missingFamilyMembers].sort((a, b) => a.localeCompare(b));
|
|
650
|
+
for (const code of sortedMissingSpecificMentionedNoFamily) {
|
|
611
651
|
const stepRef = mentionedCodeFirstStep.get(code) || 'Step ?';
|
|
612
652
|
appendMentionedButNotLinked(code, stepRef);
|
|
613
653
|
}
|
|
614
|
-
for (const
|
|
654
|
+
for (const baseKey of sortedMissingBaseWhenFamilyUncovered) {
|
|
655
|
+
const stepRef = mentionedBaseFirstStep.get(baseKey) || 'Step ?';
|
|
656
|
+
appendMentionedButNotLinked(baseKey, stepRef);
|
|
657
|
+
}
|
|
658
|
+
for (const code of sortedMissingFamilyMembers) {
|
|
615
659
|
const baseKey = this.toRequirementKey(code);
|
|
616
660
|
const stepRef = mentionedBaseFirstStep.get(baseKey) || 'Step ?';
|
|
617
661
|
appendMentionedButNotLinked(code, stepRef);
|
|
@@ -634,18 +678,20 @@ class ResultDataProvider {
|
|
|
634
678
|
return String(a[0]).localeCompare(String(b[0]));
|
|
635
679
|
})
|
|
636
680
|
.map(([stepRef, requirementIds]) => {
|
|
637
|
-
const
|
|
638
|
-
return `${stepRef}: ${
|
|
681
|
+
const groupedRequirementList = this.formatRequirementCodesGroupedByFamily(requirementIds);
|
|
682
|
+
return `${stepRef}: ${groupedRequirementList}`;
|
|
639
683
|
})
|
|
640
684
|
.join('; ');
|
|
641
|
-
const linkedButNotMentioned =
|
|
685
|
+
const linkedButNotMentioned = this.formatRequirementCodesGroupedByFamily(sortedExtraLinked);
|
|
642
686
|
const validationStatus = mentionedButNotLinked || linkedButNotMentioned ? 'Fail' : 'Pass';
|
|
643
687
|
if (validationStatus === 'Fail')
|
|
644
688
|
diagnostics.failingRows += 1;
|
|
645
689
|
logger_1.default.debug(`MEWP internal validation parse diagnostics: ` +
|
|
646
690
|
`testCaseId=${testCaseId} parsedSteps=${executableSteps.length} ` +
|
|
647
691
|
`stepsWithMentions=${mentionEntries.length} customerIdsFound=${mentionedL2Only.size} ` +
|
|
648
|
-
`linkedRequirements=${linkedFullCodes.size} mentionedButNotLinked=${
|
|
692
|
+
`linkedRequirements=${linkedFullCodes.size} mentionedButNotLinked=${sortedMissingSpecificMentionedNoFamily.length +
|
|
693
|
+
sortedMissingBaseWhenFamilyUncovered.length +
|
|
694
|
+
sortedMissingFamilyMembers.length} ` +
|
|
649
695
|
`linkedButNotMentioned=${sortedExtraLinked.length} status=${validationStatus} ` +
|
|
650
696
|
`customerIdSample='${[...mentionedL2Only].slice(0, 5).join(', ')}'`);
|
|
651
697
|
rows.push({
|
|
@@ -2225,6 +2271,29 @@ class ResultDataProvider {
|
|
|
2225
2271
|
return `SR${match[1]}-${match[2]}`;
|
|
2226
2272
|
return `SR${match[1]}`;
|
|
2227
2273
|
}
|
|
2274
|
+
formatRequirementCodesGroupedByFamily(codes) {
|
|
2275
|
+
const byBaseKey = new Map();
|
|
2276
|
+
for (const rawCode of codes || []) {
|
|
2277
|
+
const normalizedCode = this.normalizeMewpRequirementCodeWithSuffix(String(rawCode || ''));
|
|
2278
|
+
if (!normalizedCode)
|
|
2279
|
+
continue;
|
|
2280
|
+
const baseKey = this.toRequirementKey(normalizedCode) || normalizedCode;
|
|
2281
|
+
if (!byBaseKey.has(baseKey))
|
|
2282
|
+
byBaseKey.set(baseKey, new Set());
|
|
2283
|
+
byBaseKey.get(baseKey).add(normalizedCode);
|
|
2284
|
+
}
|
|
2285
|
+
if (byBaseKey.size === 0)
|
|
2286
|
+
return '';
|
|
2287
|
+
return [...byBaseKey.entries()]
|
|
2288
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
2289
|
+
.map(([baseKey, members]) => {
|
|
2290
|
+
const sortedMembers = [...members].sort((a, b) => a.localeCompare(b));
|
|
2291
|
+
if (sortedMembers.length <= 1)
|
|
2292
|
+
return sortedMembers[0];
|
|
2293
|
+
return `${baseKey}: ${sortedMembers.join(', ')}`;
|
|
2294
|
+
})
|
|
2295
|
+
.join('; ');
|
|
2296
|
+
}
|
|
2228
2297
|
toMewpComparableText(value) {
|
|
2229
2298
|
if (value === null || value === undefined)
|
|
2230
2299
|
return '';
|