@elisra-devops/docgen-data-provider 1.99.0 → 1.101.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.
@@ -227,7 +227,14 @@ export default class ResultDataProvider {
227
227
  * Returns true when the snapshot includes a non-empty test steps XML payload.
228
228
  */
229
229
  private hasStepsInWorkItemSnapshot;
230
- private logRunlessSnapshotDecision;
230
+ /**
231
+ * Resolves the suite-aware revision for a test point.
232
+ */
233
+ private resolvePointRevision;
234
+ /**
235
+ * Builds ordered keys used to match a point with fetched iteration payloads.
236
+ */
237
+ private buildIterationLookupCandidates;
231
238
  /**
232
239
  * Resolves runless test case data using ordered fallbacks:
233
240
  * 1) point-based `asOf` snapshot, 2) explicit revision, 3) suite payload snapshot, 4) latest WI.
@@ -338,6 +345,12 @@ export default class ResultDataProvider {
338
345
  * Creates a mapping of iterations by their unique keys.
339
346
  */
340
347
  private createIterationsMap;
348
+ /**
349
+ * Builds a stable lookup key for joining points to fetched iteration payloads.
350
+ * Run-backed items are keyed by run/result/testCase, while runless items prefer
351
+ * testPointId to avoid collisions across suites that share the same testCaseId.
352
+ */
353
+ private buildIterationLookupKey;
341
354
  /**
342
355
  * Fetches test data for all suites, including test points and test cases.
343
356
  */
@@ -2764,7 +2764,6 @@ class ResultDataProvider {
2764
2764
  const parsedAsOf = new Date(String(asOfTimestamp || '').trim());
2765
2765
  if (!Number.isFinite(id) || id <= 0 || Number.isNaN(parsedAsOf.getTime()))
2766
2766
  return null;
2767
- logger_1.default.debug(`[RunlessResolver] Fetching work item ${id} by asOf (raw="${String(asOfTimestamp || '')}", normalized="${parsedAsOf.toISOString()}", expandAll=${String(expandAll)})`);
2768
2767
  const query = [`asOf=${encodeURIComponent(parsedAsOf.toISOString())}`];
2769
2768
  if (expandAll) {
2770
2769
  query.push(`$expand=all`);
@@ -2799,15 +2798,34 @@ class ResultDataProvider {
2799
2798
  const stepsXml = this.extractStepsXmlFromFieldsMap((workItemData === null || workItemData === void 0 ? void 0 : workItemData.fields) || {});
2800
2799
  return String(stepsXml || '').trim() !== '';
2801
2800
  }
2802
- logRunlessSnapshotDecision(testCaseId, source, snapshot) {
2803
- var _a;
2804
- if (!snapshot) {
2805
- logger_1.default.debug(`[RunlessResolver] TC ${testCaseId}: source=${source}, snapshot=none`);
2806
- return;
2801
+ /**
2802
+ * Resolves the suite-aware revision for a test point.
2803
+ */
2804
+ resolvePointRevision(testCase, point) {
2805
+ return Number(this.resolveSuiteTestCaseRevision(testCase) ||
2806
+ this.resolveSuiteTestCaseRevision(point === null || point === void 0 ? void 0 : point.suiteTestCase) ||
2807
+ 0);
2808
+ }
2809
+ /**
2810
+ * Builds ordered keys used to match a point with fetched iteration payloads.
2811
+ */
2812
+ buildIterationLookupCandidates(input) {
2813
+ const candidates = [];
2814
+ const addCandidate = (key) => {
2815
+ if (key && !candidates.includes(key)) {
2816
+ candidates.push(key);
2817
+ }
2818
+ };
2819
+ addCandidate(this.buildIterationLookupKey(input));
2820
+ const revision = Number((input === null || input === void 0 ? void 0 : input.testCaseRevision) || 0);
2821
+ if (Number.isFinite(revision) && revision > 0) {
2822
+ addCandidate(this.buildIterationLookupKey({
2823
+ testCaseId: input === null || input === void 0 ? void 0 : input.testCaseId,
2824
+ testCaseRevision: revision,
2825
+ }));
2807
2826
  }
2808
- const stepsXml = this.extractStepsXmlFromFieldsMap((snapshot === null || snapshot === void 0 ? void 0 : snapshot.fields) || {});
2809
- const stepsLength = String(stepsXml || '').trim().length;
2810
- logger_1.default.debug(`[RunlessResolver] TC ${testCaseId}: source=${source}, rev=${String((_a = snapshot === null || snapshot === void 0 ? void 0 : snapshot.rev) !== null && _a !== void 0 ? _a : '')}, hasSteps=${String(stepsLength > 0)}, stepsLength=${String(stepsLength)}`);
2827
+ addCandidate(`${Number((input === null || input === void 0 ? void 0 : input.testCaseId) || 0)}`);
2828
+ return candidates;
2811
2829
  }
2812
2830
  /**
2813
2831
  * Resolves runless test case data using ordered fallbacks:
@@ -2817,31 +2835,24 @@ class ResultDataProvider {
2817
2835
  let bestSnapshotWithoutSteps = null;
2818
2836
  if (pointAsOfTimestamp) {
2819
2837
  const asOfSnapshot = await this.fetchWorkItemByAsOf(projectName, testCaseId, pointAsOfTimestamp, expandAll);
2820
- this.logRunlessSnapshotDecision(testCaseId, 'asOf', asOfSnapshot);
2821
2838
  if (asOfSnapshot) {
2822
2839
  if (this.hasStepsInWorkItemSnapshot(asOfSnapshot))
2823
2840
  return asOfSnapshot;
2824
2841
  bestSnapshotWithoutSteps = asOfSnapshot;
2825
2842
  }
2826
2843
  }
2827
- else {
2828
- logger_1.default.debug(`[RunlessResolver] TC ${testCaseId}: asOf timestamp is empty, skipping asOf fetch`);
2829
- }
2830
2844
  const revisionSnapshot = await this.fetchWorkItemByRevision(projectName, testCaseId, suiteTestCaseRevision, expandAll);
2831
- this.logRunlessSnapshotDecision(testCaseId, `revision:${String(suiteTestCaseRevision)}`, revisionSnapshot);
2832
2845
  if (revisionSnapshot) {
2833
2846
  if (this.hasStepsInWorkItemSnapshot(revisionSnapshot))
2834
2847
  return revisionSnapshot;
2835
2848
  bestSnapshotWithoutSteps = bestSnapshotWithoutSteps || revisionSnapshot;
2836
2849
  }
2837
- this.logRunlessSnapshotDecision(testCaseId, 'suiteSnapshot', fallbackSnapshot);
2838
2850
  if (fallbackSnapshot) {
2839
2851
  if (this.hasStepsInWorkItemSnapshot(fallbackSnapshot))
2840
2852
  return fallbackSnapshot;
2841
2853
  bestSnapshotWithoutSteps = bestSnapshotWithoutSteps || fallbackSnapshot;
2842
2854
  }
2843
2855
  const latestSnapshot = await this.fetchWorkItemLatest(projectName, testCaseId, expandAll);
2844
- this.logRunlessSnapshotDecision(testCaseId, 'latest', latestSnapshot);
2845
2856
  if (latestSnapshot) {
2846
2857
  if (this.hasStepsInWorkItemSnapshot(latestSnapshot))
2847
2858
  return latestSnapshot;
@@ -2881,7 +2892,6 @@ class ResultDataProvider {
2881
2892
  const pointAsOfTimestamp = useRunlessAsOf
2882
2893
  ? String((point === null || point === void 0 ? void 0 : point.pointAsOfTimestamp) || '').trim()
2883
2894
  : '';
2884
- logger_1.default.debug(`[RunlessResolver] Start TC ${String(testCaseId)}: useRunlessAsOf=${String(useRunlessAsOf)}, pointAsOfTimestamp="${pointAsOfTimestamp}", suiteRevision=${String(suiteTestCaseRevision)}, pointOutcome="${String((point === null || point === void 0 ? void 0 : point.outcome) || '')}"`);
2885
2895
  const fallbackSnapshot = this.buildWorkItemSnapshotFromSuiteTestCase(suiteTestCaseItem, testCaseId, String((point === null || point === void 0 ? void 0 : point.testCaseName) || ''));
2886
2896
  const testCaseData = await this.resolveRunlessTestCaseData(projectName, testCaseId, suiteTestCaseRevision, pointAsOfTimestamp, fallbackSnapshot, isTestReporter);
2887
2897
  if (!testCaseData) {
@@ -3522,9 +3532,6 @@ class ResultDataProvider {
3522
3532
  };
3523
3533
  if (!Number.isFinite(pointTestCaseId) || pointTestCaseId <= 0)
3524
3534
  continue;
3525
- if (!testCaseById.has(pointTestCaseId) && isTestReporter) {
3526
- logger_1.default.debug(`[RunlessResolver] Missing suite testCase payload for point testCaseId=${String(pointTestCaseId)}; using point fallback for alignment`);
3527
- }
3528
3535
  const testCaseWorkItemFields = Array.isArray((_d = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _d === void 0 ? void 0 : _d.workItemFields)
3529
3536
  ? testCase.workItem.workItemFields
3530
3537
  : [];
@@ -3534,10 +3541,16 @@ class ResultDataProvider {
3534
3541
  continue;
3535
3542
  }
3536
3543
  }
3537
- const iterationKey = !point.lastRunId || !point.lastResultId
3538
- ? `${testCase.workItem.id}`
3539
- : `${point.lastRunId}-${point.lastResultId}-${testCase.workItem.id}`;
3540
- const fetchedTestCase = iterationsMap[iterationKey] || (includeNotRunTestCases ? testCase : undefined);
3544
+ const iterationLookupKeys = this.buildIterationLookupCandidates({
3545
+ testCaseId: testCase.workItem.id,
3546
+ lastRunId: point === null || point === void 0 ? void 0 : point.lastRunId,
3547
+ lastResultId: point === null || point === void 0 ? void 0 : point.lastResultId,
3548
+ testPointId: point === null || point === void 0 ? void 0 : point.testPointId,
3549
+ testCaseRevision: this.resolvePointRevision(testCase, point),
3550
+ });
3551
+ const fetchedTestCaseFromMap = iterationLookupKeys.find((key) => iterationsMap[key]) || '';
3552
+ const fetchedTestCase = (fetchedTestCaseFromMap ? iterationsMap[fetchedTestCaseFromMap] : undefined) ||
3553
+ (includeNotRunTestCases ? testCase : undefined);
3541
3554
  // First check if fetchedTestCase exists
3542
3555
  if (!fetchedTestCase)
3543
3556
  continue;
@@ -3590,7 +3603,6 @@ class ResultDataProvider {
3590
3603
  detailedResults.push(...resultObjectsToAdd);
3591
3604
  }
3592
3605
  else {
3593
- logger_1.default.debug(`[RunlessResolver] No step rows generated for testCaseId=${String((point === null || point === void 0 ? void 0 : point.testCaseId) || '')}; falling back to test-level row`);
3594
3606
  detailedResults.push(options.createResultObject({
3595
3607
  testItem,
3596
3608
  point,
@@ -3649,23 +3661,64 @@ class ResultDataProvider {
3649
3661
  (iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.lastResultId) !== null &&
3650
3662
  String(iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.lastResultId).trim() !== '';
3651
3663
  if (hasRunIdentifiers) {
3652
- const key = `${iterationItem.lastRunId}-${iterationItem.lastResultId}-${iterationItem.testCaseId}`;
3664
+ const key = this.buildIterationLookupKey({
3665
+ testCaseId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseId,
3666
+ lastRunId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.lastRunId,
3667
+ lastResultId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.lastResultId,
3668
+ testPointId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testPointId,
3669
+ testCaseRevision: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseRevision,
3670
+ });
3653
3671
  map[key] = iterationItem;
3654
3672
  }
3655
3673
  else if (includeNotRunTestCases) {
3656
- const key = `${iterationItem.testCaseId}`;
3674
+ const key = this.buildIterationLookupKey({
3675
+ testCaseId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseId,
3676
+ lastRunId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.lastRunId,
3677
+ lastResultId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.lastResultId,
3678
+ testPointId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testPointId,
3679
+ testCaseRevision: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseRevision,
3680
+ });
3657
3681
  map[key] = iterationItem;
3658
- if (isTestReporter && (iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.iteration)) {
3659
- logger_1.default.debug(`[RunlessResolver] createIterationsMap: mapped runless testCaseId=${String(iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseId)} to case-only key`);
3660
- }
3661
3682
  }
3662
3683
  else if ((iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.iteration) && !isTestReporter) {
3663
- const key = `${iterationItem.lastRunId}-${iterationItem.lastResultId}-${iterationItem.testCaseId}`;
3684
+ const key = this.buildIterationLookupKey({
3685
+ testCaseId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseId,
3686
+ lastRunId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.lastRunId,
3687
+ lastResultId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.lastResultId,
3688
+ testPointId: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testPointId,
3689
+ testCaseRevision: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseRevision,
3690
+ });
3664
3691
  map[key] = iterationItem;
3665
3692
  }
3666
3693
  return map;
3667
3694
  }, {});
3668
3695
  }
3696
+ /**
3697
+ * Builds a stable lookup key for joining points to fetched iteration payloads.
3698
+ * Run-backed items are keyed by run/result/testCase, while runless items prefer
3699
+ * testPointId to avoid collisions across suites that share the same testCaseId.
3700
+ */
3701
+ buildIterationLookupKey(input) {
3702
+ const testCaseId = Number((input === null || input === void 0 ? void 0 : input.testCaseId) || 0);
3703
+ const hasRunIdentifiers = (input === null || input === void 0 ? void 0 : input.lastRunId) !== undefined &&
3704
+ (input === null || input === void 0 ? void 0 : input.lastRunId) !== null &&
3705
+ String(input === null || input === void 0 ? void 0 : input.lastRunId).trim() !== '' &&
3706
+ (input === null || input === void 0 ? void 0 : input.lastResultId) !== undefined &&
3707
+ (input === null || input === void 0 ? void 0 : input.lastResultId) !== null &&
3708
+ String(input === null || input === void 0 ? void 0 : input.lastResultId).trim() !== '';
3709
+ if (hasRunIdentifiers) {
3710
+ return `${input === null || input === void 0 ? void 0 : input.lastRunId}-${input === null || input === void 0 ? void 0 : input.lastResultId}-${testCaseId}`;
3711
+ }
3712
+ const testPointId = Number((input === null || input === void 0 ? void 0 : input.testPointId) || 0);
3713
+ if (Number.isFinite(testPointId) && testPointId > 0) {
3714
+ return `point-${testPointId}-${testCaseId}`;
3715
+ }
3716
+ const testCaseRevision = Number((input === null || input === void 0 ? void 0 : input.testCaseRevision) || 0);
3717
+ if (Number.isFinite(testCaseRevision) && testCaseRevision > 0) {
3718
+ return `rev-${testCaseId}-${testCaseRevision}`;
3719
+ }
3720
+ return `${testCaseId}`;
3721
+ }
3669
3722
  /**
3670
3723
  * Fetches test data for all suites, including test points and test cases.
3671
3724
  */
@@ -3755,7 +3808,7 @@ class ResultDataProvider {
3755
3808
  * Fetches result Data for a specific test point
3756
3809
  */
3757
3810
  async fetchResultDataBase(projectName, testSuiteId, point, fetchResultMethod, createResponseObject, additionalArgs = []) {
3758
- var _a, _b, _c, _d, _e, _f;
3811
+ var _a;
3759
3812
  try {
3760
3813
  const { lastRunId, lastResultId } = point;
3761
3814
  const resultData = await fetchResultMethod(projectName, (lastRunId === null || lastRunId === void 0 ? void 0 : lastRunId.toString()) || '0', (lastResultId === null || lastResultId === void 0 ? void 0 : lastResultId.toString()) || '0', ...additionalArgs);
@@ -3780,7 +3833,6 @@ class ResultDataProvider {
3780
3833
  });
3781
3834
  }
3782
3835
  const stepsList = await this.testStepParserHelper.parseTestSteps(resultData.stepsResultXml, sharedStepIdToRevisionLookupMap);
3783
- logger_1.default.debug(`[RunlessResolver] TC ${String((point === null || point === void 0 ? void 0 : point.testCaseId) || ((_b = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _b === void 0 ? void 0 : _b.id) || '')}: parseTestSteps xmlLength=${String(String(resultData.stepsResultXml || '').length)}, parsedSteps=${String(stepsList.length)}, actionResultsBeforeMap=${String(actionResults.length)}`);
3784
3836
  sharedStepIdToRevisionLookupMap.clear();
3785
3837
  const stepMap = new Map();
3786
3838
  for (const step of stepsList) {
@@ -3800,7 +3852,6 @@ class ResultDataProvider {
3800
3852
  iteration.actionResults = actionResults
3801
3853
  .filter((result) => result.stepPosition)
3802
3854
  .sort((a, b) => this.compareActionResults(a.stepPosition, b.stepPosition));
3803
- logger_1.default.debug(`[RunlessResolver] TC ${String((point === null || point === void 0 ? void 0 : point.testCaseId) || ((_c = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _c === void 0 ? void 0 : _c.id) || '')}: mappedActionResults=${String(((_d = iteration.actionResults) === null || _d === void 0 ? void 0 : _d.length) || 0)} (from existing iteration actionResults)`);
3804
3855
  }
3805
3856
  else {
3806
3857
  // Fallback for runs that have no action results: emit test definition steps as Not Run.
@@ -3820,7 +3871,6 @@ class ResultDataProvider {
3820
3871
  });
3821
3872
  })
3822
3873
  .sort((a, b) => this.compareActionResults(a.stepPosition, b.stepPosition));
3823
- logger_1.default.debug(`[RunlessResolver] TC ${String((point === null || point === void 0 ? void 0 : point.testCaseId) || ((_e = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _e === void 0 ? void 0 : _e.id) || '')}: fallbackActionResults=${String(((_f = iteration.actionResults) === null || _f === void 0 ? void 0 : _f.length) || 0)} (from parsed steps)`);
3824
3874
  }
3825
3875
  }
3826
3876
  return (resultData === null || resultData === void 0 ? void 0 : resultData.testCase)
@@ -4326,6 +4376,7 @@ class ResultDataProvider {
4326
4376
  const resultDataResponse = {
4327
4377
  testCaseName: `${(_e = (_d = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : ''} - ${(_g = (_f = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _f === void 0 ? void 0 : _f.id) !== null && _g !== void 0 ? _g : ''}`,
4328
4378
  testCaseId: (_h = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _h === void 0 ? void 0 : _h.id,
4379
+ testPointId: point === null || point === void 0 ? void 0 : point.testPointId,
4329
4380
  testSuiteName: `${(_k = (_j = resultData === null || resultData === void 0 ? void 0 : resultData.testSuite) === null || _j === void 0 ? void 0 : _j.name) !== null && _k !== void 0 ? _k : ''}`,
4330
4381
  testSuiteId,
4331
4382
  lastRunId,