@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.
@@ -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): Promise<MewpInternalValidationFlatPayload>;
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 normalizedFamilyMembers = [...familyCodes]
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
- for (const code of mentionedSpecificMembers) {
625
- if (!familyLinkedCodes.has(code)) {
626
- missingSpecificMentionedNoFamily.add(code);
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(`MEWP internal validation parse diagnostics: ` +
717
- `testCaseId=${testCaseId} parsedSteps=${executableSteps.length} ` +
718
- `stepsWithMentions=${mentionEntries.length} customerIdsFound=${mentionedL2Only.size} ` +
719
- `linkedRequirements=${linkedFullCodes.size} mentionedButNotLinked=${sortedMissingSpecificMentionedNoFamily.length +
720
- sortedMissingBaseWhenFamilyUncovered.length} ` +
721
- `linkedButNotMentioned=${sortedExtraLinked.length} status=${validationStatus} ` +
722
- `customerIdSample='${[...mentionedL2Only].slice(0, 5).join(', ')}'`);
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(`MEWP internal validation summary: testCases=${diagnostics.totalTestCases} ` +
732
- `parsedSteps=${diagnostics.totalParsedSteps} stepsWithMentions=${diagnostics.totalStepsWithMentions} ` +
733
- `totalCustomerIdsFound=${diagnostics.totalMentionedCustomerIds} ` +
734
- `testCasesWithoutCustomerIds=${diagnostics.testCasesWithoutMentionedCustomerIds} ` +
735
- `failingRows=${diagnostics.failingRows}`);
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('\n');
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',