@elisra-devops/docgen-data-provider 1.90.0 → 1.91.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 +92 -47
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +97 -3
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +102 -53
- package/src/tests/modules/ResultDataProvider.test.ts +112 -3
|
@@ -138,6 +138,8 @@ export default class ResultDataProvider {
|
|
|
138
138
|
private isExcludedL3L4BySapWbs;
|
|
139
139
|
private normalizeMewpRequirementCode;
|
|
140
140
|
private normalizeMewpRequirementCodeWithSuffix;
|
|
141
|
+
private compareMewpRequirementCodes;
|
|
142
|
+
private formatStepScopedRequirementGroups;
|
|
141
143
|
private formatRequirementCodesGroupedByFamily;
|
|
142
144
|
private toMewpComparableText;
|
|
143
145
|
private fetchTestPlanName;
|
|
@@ -476,7 +476,7 @@ class ResultDataProvider {
|
|
|
476
476
|
}
|
|
477
477
|
}
|
|
478
478
|
async getMewpInternalValidationFlatResults(testPlanId, projectName, selectedSuiteIds, linkedQueryRequest) {
|
|
479
|
-
var _a, _b
|
|
479
|
+
var _a, _b;
|
|
480
480
|
const defaultPayload = {
|
|
481
481
|
sheetName: `MEWP Internal Validation - Plan ${testPlanId}`,
|
|
482
482
|
columnOrder: [...ResultDataProvider.INTERNAL_VALIDATION_COLUMNS],
|
|
@@ -489,6 +489,31 @@ class ResultDataProvider {
|
|
|
489
489
|
const linkedRequirementsByTestCase = await this.buildLinkedRequirementsByTestCase(allRequirements, testData, projectName);
|
|
490
490
|
const scopedRequirementKeys = await this.resolveMewpRequirementScopeKeysFromQuery(linkedQueryRequest, allRequirements, linkedRequirementsByTestCase);
|
|
491
491
|
const requirementFamilies = this.buildRequirementFamilyMap(allRequirements, (scopedRequirementKeys === null || scopedRequirementKeys === void 0 ? void 0 : scopedRequirementKeys.size) ? scopedRequirementKeys : undefined);
|
|
492
|
+
const linkedFullCodesByTestCase = new Map();
|
|
493
|
+
const linkedFamilyCodesAcrossTestCases = new Map();
|
|
494
|
+
const linkedFullCodesAcrossTestCases = new Set();
|
|
495
|
+
const linkedBaseKeysAcrossTestCases = new Set();
|
|
496
|
+
for (const [linkedTestCaseId, links] of linkedRequirementsByTestCase.entries()) {
|
|
497
|
+
const rawFullCodes = (links === null || links === void 0 ? void 0 : links.fullCodes) || new Set();
|
|
498
|
+
const filteredFullCodes = (scopedRequirementKeys === null || scopedRequirementKeys === void 0 ? void 0 : scopedRequirementKeys.size) && rawFullCodes.size > 0
|
|
499
|
+
? new Set([...rawFullCodes].filter((code) => scopedRequirementKeys.has(this.toRequirementKey(code))))
|
|
500
|
+
: rawFullCodes;
|
|
501
|
+
linkedFullCodesByTestCase.set(linkedTestCaseId, filteredFullCodes);
|
|
502
|
+
for (const code of filteredFullCodes) {
|
|
503
|
+
const normalizedCode = this.normalizeMewpRequirementCodeWithSuffix(code);
|
|
504
|
+
if (!normalizedCode)
|
|
505
|
+
continue;
|
|
506
|
+
linkedFullCodesAcrossTestCases.add(normalizedCode);
|
|
507
|
+
const baseKey = this.toRequirementKey(normalizedCode);
|
|
508
|
+
if (!baseKey)
|
|
509
|
+
continue;
|
|
510
|
+
linkedBaseKeysAcrossTestCases.add(baseKey);
|
|
511
|
+
if (!linkedFamilyCodesAcrossTestCases.has(baseKey)) {
|
|
512
|
+
linkedFamilyCodesAcrossTestCases.set(baseKey, new Set());
|
|
513
|
+
}
|
|
514
|
+
linkedFamilyCodesAcrossTestCases.get(baseKey).add(normalizedCode);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
492
517
|
const rows = [];
|
|
493
518
|
const stepsXmlByTestCase = this.buildTestCaseStepsXmlMap(testData);
|
|
494
519
|
const testCaseTitleMap = this.buildMewpTestCaseTitleMap(testData);
|
|
@@ -558,11 +583,7 @@ class ResultDataProvider {
|
|
|
558
583
|
diagnostics.testCasesWithoutMentionedCustomerIds += 1;
|
|
559
584
|
}
|
|
560
585
|
const mentionedBaseKeys = new Set([...mentionedL2Only].map((code) => this.toRequirementKey(code)).filter((code) => !!code));
|
|
561
|
-
const
|
|
562
|
-
const linkedFullCodes = (scopedRequirementKeys === null || scopedRequirementKeys === void 0 ? void 0 : scopedRequirementKeys.size) && linkedFullCodesRaw.size > 0
|
|
563
|
-
? new Set([...linkedFullCodesRaw].filter((code) => scopedRequirementKeys.has(this.toRequirementKey(code))))
|
|
564
|
-
: linkedFullCodesRaw;
|
|
565
|
-
const linkedBaseKeys = new Set([...linkedFullCodes].map((code) => this.toRequirementKey(code)).filter((code) => !!code));
|
|
586
|
+
const linkedFullCodes = linkedFullCodesByTestCase.get(testCaseId) || new Set();
|
|
566
587
|
const mentionedCodesByBase = new Map();
|
|
567
588
|
for (const code of mentionedL2Only) {
|
|
568
589
|
const baseKey = this.toRequirementKey(code);
|
|
@@ -572,42 +593,28 @@ class ResultDataProvider {
|
|
|
572
593
|
mentionedCodesByBase.set(baseKey, new Set());
|
|
573
594
|
mentionedCodesByBase.get(baseKey).add(code);
|
|
574
595
|
}
|
|
575
|
-
//
|
|
576
|
-
// 1)
|
|
577
|
-
//
|
|
578
|
-
//
|
|
596
|
+
// Direction A logic:
|
|
597
|
+
// 1) Base mention ("SR0054") is parent-level only and considered covered
|
|
598
|
+
// if any member of that family is linked across scoped test cases.
|
|
599
|
+
// 2) Child mention ("SR0054-1") is exact-match and checked across scoped test cases.
|
|
579
600
|
const missingBaseWhenFamilyUncovered = new Set();
|
|
580
601
|
const missingSpecificMentionedNoFamily = new Set();
|
|
581
|
-
const missingFamilyMembers = new Set();
|
|
582
602
|
for (const [baseKey, mentionedCodes] of mentionedCodesByBase.entries()) {
|
|
583
603
|
const familyCodes = requirementFamilies.get(baseKey);
|
|
584
604
|
const mentionedCodesList = [...mentionedCodes];
|
|
585
605
|
const hasBaseMention = mentionedCodesList.some((code) => !/-\d+$/.test(code));
|
|
586
606
|
const mentionedSpecificMembers = mentionedCodesList.filter((code) => /-\d+$/.test(code));
|
|
587
607
|
if (familyCodes === null || familyCodes === void 0 ? void 0 : familyCodes.size) {
|
|
588
|
-
|
|
589
|
-
//
|
|
608
|
+
const familyLinkedCodes = linkedFamilyCodesAcrossTestCases.get(baseKey) || new Set();
|
|
609
|
+
// Base mention ("SR0054") is satisfied by any linked member in the same family.
|
|
590
610
|
if (hasBaseMention) {
|
|
591
|
-
|
|
592
|
-
|
|
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
|
-
}
|
|
611
|
+
if (familyLinkedCodes.size === 0) {
|
|
612
|
+
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
605
613
|
}
|
|
606
|
-
continue;
|
|
607
614
|
}
|
|
608
|
-
// Specific mention ("SR0054-1") validates as exact-match only.
|
|
615
|
+
// Specific mention ("SR0054-1") validates as exact-match only across scoped test cases.
|
|
609
616
|
for (const code of mentionedSpecificMembers) {
|
|
610
|
-
if (!
|
|
617
|
+
if (!familyLinkedCodes.has(code)) {
|
|
611
618
|
missingSpecificMentionedNoFamily.add(code);
|
|
612
619
|
}
|
|
613
620
|
}
|
|
@@ -617,11 +624,11 @@ class ResultDataProvider {
|
|
|
617
624
|
for (const code of mentionedCodes) {
|
|
618
625
|
const hasSpecificSuffix = /-\d+$/.test(code);
|
|
619
626
|
if (hasSpecificSuffix) {
|
|
620
|
-
if (!
|
|
627
|
+
if (!linkedFullCodesAcrossTestCases.has(code)) {
|
|
621
628
|
missingSpecificMentionedNoFamily.add(code);
|
|
622
629
|
}
|
|
623
630
|
}
|
|
624
|
-
else if (!
|
|
631
|
+
else if (!linkedBaseKeysAcrossTestCases.has(baseKey)) {
|
|
625
632
|
missingBaseWhenFamilyUncovered.add(baseKey);
|
|
626
633
|
}
|
|
627
634
|
}
|
|
@@ -647,7 +654,6 @@ class ResultDataProvider {
|
|
|
647
654
|
};
|
|
648
655
|
const sortedMissingSpecificMentionedNoFamily = [...missingSpecificMentionedNoFamily].sort((a, b) => a.localeCompare(b));
|
|
649
656
|
const sortedMissingBaseWhenFamilyUncovered = [...missingBaseWhenFamilyUncovered].sort((a, b) => a.localeCompare(b));
|
|
650
|
-
const sortedMissingFamilyMembers = [...missingFamilyMembers].sort((a, b) => a.localeCompare(b));
|
|
651
657
|
for (const code of sortedMissingSpecificMentionedNoFamily) {
|
|
652
658
|
const stepRef = mentionedCodeFirstStep.get(code) || 'Step ?';
|
|
653
659
|
appendMentionedButNotLinked(code, stepRef);
|
|
@@ -656,11 +662,6 @@ class ResultDataProvider {
|
|
|
656
662
|
const stepRef = mentionedBaseFirstStep.get(baseKey) || 'Step ?';
|
|
657
663
|
appendMentionedButNotLinked(baseKey, stepRef);
|
|
658
664
|
}
|
|
659
|
-
for (const code of sortedMissingFamilyMembers) {
|
|
660
|
-
const baseKey = this.toRequirementKey(code);
|
|
661
|
-
const stepRef = mentionedBaseFirstStep.get(baseKey) || 'Step ?';
|
|
662
|
-
appendMentionedButNotLinked(code, stepRef);
|
|
663
|
-
}
|
|
664
665
|
const sortedExtraLinked = [...new Set(extraLinked)]
|
|
665
666
|
.map((code) => this.normalizeMewpRequirementCodeWithSuffix(code))
|
|
666
667
|
.filter((code) => !!code)
|
|
@@ -679,11 +680,11 @@ class ResultDataProvider {
|
|
|
679
680
|
return String(a[0]).localeCompare(String(b[0]));
|
|
680
681
|
})
|
|
681
682
|
.map(([stepRef, requirementIds]) => {
|
|
682
|
-
|
|
683
|
-
return `${stepRef}: ${groupedRequirementList}`;
|
|
683
|
+
return this.formatStepScopedRequirementGroups(stepRef, requirementIds);
|
|
684
684
|
})
|
|
685
|
-
.join('\n')
|
|
686
|
-
|
|
685
|
+
.join('\n')
|
|
686
|
+
.trim();
|
|
687
|
+
const linkedButNotMentioned = this.formatRequirementCodesGroupedByFamily(sortedExtraLinked).trim();
|
|
687
688
|
const validationStatus = mentionedButNotLinked || linkedButNotMentioned ? 'Fail' : 'Pass';
|
|
688
689
|
if (validationStatus === 'Fail')
|
|
689
690
|
diagnostics.failingRows += 1;
|
|
@@ -691,8 +692,7 @@ class ResultDataProvider {
|
|
|
691
692
|
`testCaseId=${testCaseId} parsedSteps=${executableSteps.length} ` +
|
|
692
693
|
`stepsWithMentions=${mentionEntries.length} customerIdsFound=${mentionedL2Only.size} ` +
|
|
693
694
|
`linkedRequirements=${linkedFullCodes.size} mentionedButNotLinked=${sortedMissingSpecificMentionedNoFamily.length +
|
|
694
|
-
sortedMissingBaseWhenFamilyUncovered.length +
|
|
695
|
-
sortedMissingFamilyMembers.length} ` +
|
|
695
|
+
sortedMissingBaseWhenFamilyUncovered.length} ` +
|
|
696
696
|
`linkedButNotMentioned=${sortedExtraLinked.length} status=${validationStatus} ` +
|
|
697
697
|
`customerIdSample='${[...mentionedL2Only].slice(0, 5).join(', ')}'`);
|
|
698
698
|
rows.push({
|
|
@@ -2145,6 +2145,47 @@ class ResultDataProvider {
|
|
|
2145
2145
|
return `SR${match[1]}-${match[2]}`;
|
|
2146
2146
|
return `SR${match[1]}`;
|
|
2147
2147
|
}
|
|
2148
|
+
compareMewpRequirementCodes(a, b) {
|
|
2149
|
+
const normalizeComparableCode = (value) => {
|
|
2150
|
+
const normalizedCode = this.normalizeMewpRequirementCodeWithSuffix(value);
|
|
2151
|
+
const match = /^SR(\d+)(?:-(\d+))?$/i.exec(normalizedCode);
|
|
2152
|
+
if (!match) {
|
|
2153
|
+
return {
|
|
2154
|
+
base: Number.POSITIVE_INFINITY,
|
|
2155
|
+
hasSuffix: 1,
|
|
2156
|
+
suffix: Number.POSITIVE_INFINITY,
|
|
2157
|
+
raw: String(value || ''),
|
|
2158
|
+
};
|
|
2159
|
+
}
|
|
2160
|
+
return {
|
|
2161
|
+
base: Number(match[1]),
|
|
2162
|
+
hasSuffix: match[2] ? 1 : 0,
|
|
2163
|
+
suffix: match[2] ? Number(match[2]) : -1,
|
|
2164
|
+
raw: normalizedCode,
|
|
2165
|
+
};
|
|
2166
|
+
};
|
|
2167
|
+
const left = normalizeComparableCode(a);
|
|
2168
|
+
const right = normalizeComparableCode(b);
|
|
2169
|
+
if (left.base !== right.base)
|
|
2170
|
+
return left.base - right.base;
|
|
2171
|
+
if (left.hasSuffix !== right.hasSuffix)
|
|
2172
|
+
return left.hasSuffix - right.hasSuffix;
|
|
2173
|
+
if (left.suffix !== right.suffix)
|
|
2174
|
+
return left.suffix - right.suffix;
|
|
2175
|
+
return left.raw.localeCompare(right.raw);
|
|
2176
|
+
}
|
|
2177
|
+
formatStepScopedRequirementGroups(stepRef, requirementIds) {
|
|
2178
|
+
const groupedRequirementList = this.formatRequirementCodesGroupedByFamily(requirementIds);
|
|
2179
|
+
if (!groupedRequirementList)
|
|
2180
|
+
return `${stepRef}:`;
|
|
2181
|
+
const groupedLines = groupedRequirementList
|
|
2182
|
+
.split('\n')
|
|
2183
|
+
.map((line) => String(line || '').trim())
|
|
2184
|
+
.filter((line) => line.length > 0);
|
|
2185
|
+
if (groupedLines.length <= 1)
|
|
2186
|
+
return `${stepRef}: ${groupedLines[0] || ''}`.trim();
|
|
2187
|
+
return `${stepRef}:\n${groupedLines.map((line) => `- ${line}`).join('\n')}`.trim();
|
|
2188
|
+
}
|
|
2148
2189
|
formatRequirementCodesGroupedByFamily(codes) {
|
|
2149
2190
|
const byBaseKey = new Map();
|
|
2150
2191
|
for (const rawCode of codes || []) {
|
|
@@ -2159,12 +2200,16 @@ class ResultDataProvider {
|
|
|
2159
2200
|
if (byBaseKey.size === 0)
|
|
2160
2201
|
return '';
|
|
2161
2202
|
return [...byBaseKey.entries()]
|
|
2162
|
-
.sort((a, b) => a[0]
|
|
2203
|
+
.sort((a, b) => this.compareMewpRequirementCodes(a[0], b[0]))
|
|
2163
2204
|
.map(([baseKey, members]) => {
|
|
2164
|
-
const sortedMembers = [...members].sort((a, b) =>
|
|
2205
|
+
const sortedMembers = [...members].sort((a, b) => this.compareMewpRequirementCodes(a, b));
|
|
2165
2206
|
if (sortedMembers.length <= 1)
|
|
2166
2207
|
return sortedMembers[0];
|
|
2167
|
-
|
|
2208
|
+
const nonBaseMembers = sortedMembers.filter((member) => member !== baseKey);
|
|
2209
|
+
if (nonBaseMembers.length > 0) {
|
|
2210
|
+
return `${baseKey}: ${nonBaseMembers.join(', ')}`;
|
|
2211
|
+
}
|
|
2212
|
+
return baseKey;
|
|
2168
2213
|
})
|
|
2169
2214
|
.join('\n');
|
|
2170
2215
|
}
|