@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.
- package/bin/modules/ResultDataProvider.d.ts +14 -1
- package/bin/modules/ResultDataProvider.js +86 -35
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +267 -2
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +108 -73
- package/src/tests/modules/ResultDataProvider.test.ts +332 -2
|
@@ -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
|
-
|
|
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
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
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
|
-
|
|
2809
|
-
|
|
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
|
|
3538
|
-
|
|
3539
|
-
:
|
|
3540
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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,
|