@elisra-devops/docgen-data-provider 1.100.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 +8 -1
- package/bin/modules/ResultDataProvider.js +32 -46
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +84 -0
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +44 -87
- package/src/tests/modules/ResultDataProvider.test.ts +125 -0
|
@@ -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.
|
|
@@ -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,29 +3541,15 @@ class ResultDataProvider {
|
|
|
3534
3541
|
continue;
|
|
3535
3542
|
}
|
|
3536
3543
|
}
|
|
3537
|
-
const
|
|
3544
|
+
const iterationLookupKeys = this.buildIterationLookupCandidates({
|
|
3538
3545
|
testCaseId: testCase.workItem.id,
|
|
3539
3546
|
lastRunId: point === null || point === void 0 ? void 0 : point.lastRunId,
|
|
3540
3547
|
lastResultId: point === null || point === void 0 ? void 0 : point.lastResultId,
|
|
3541
3548
|
testPointId: point === null || point === void 0 ? void 0 : point.testPointId,
|
|
3542
|
-
testCaseRevision: this.
|
|
3543
|
-
this.resolveSuiteTestCaseRevision(point === null || point === void 0 ? void 0 : point.suiteTestCase),
|
|
3549
|
+
testCaseRevision: this.resolvePointRevision(testCase, point),
|
|
3544
3550
|
});
|
|
3545
|
-
const
|
|
3546
|
-
|
|
3547
|
-
0);
|
|
3548
|
-
const fallbackRevisionKey = Number.isFinite(fallbackRevision) && fallbackRevision > 0
|
|
3549
|
-
? this.buildIterationLookupKey({
|
|
3550
|
-
testCaseId: testCase.workItem.id,
|
|
3551
|
-
testCaseRevision: fallbackRevision,
|
|
3552
|
-
})
|
|
3553
|
-
: '';
|
|
3554
|
-
const fallbackCaseOnlyKey = `${testCase.workItem.id}`;
|
|
3555
|
-
const fetchedTestCase = iterationsMap[iterationKey] ||
|
|
3556
|
-
(fallbackRevisionKey && fallbackRevisionKey !== iterationKey
|
|
3557
|
-
? iterationsMap[fallbackRevisionKey]
|
|
3558
|
-
: undefined) ||
|
|
3559
|
-
(iterationKey !== fallbackCaseOnlyKey ? iterationsMap[fallbackCaseOnlyKey] : undefined) ||
|
|
3551
|
+
const fetchedTestCaseFromMap = iterationLookupKeys.find((key) => iterationsMap[key]) || '';
|
|
3552
|
+
const fetchedTestCase = (fetchedTestCaseFromMap ? iterationsMap[fetchedTestCaseFromMap] : undefined) ||
|
|
3560
3553
|
(includeNotRunTestCases ? testCase : undefined);
|
|
3561
3554
|
// First check if fetchedTestCase exists
|
|
3562
3555
|
if (!fetchedTestCase)
|
|
@@ -3610,7 +3603,6 @@ class ResultDataProvider {
|
|
|
3610
3603
|
detailedResults.push(...resultObjectsToAdd);
|
|
3611
3604
|
}
|
|
3612
3605
|
else {
|
|
3613
|
-
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`);
|
|
3614
3606
|
detailedResults.push(options.createResultObject({
|
|
3615
3607
|
testItem,
|
|
3616
3608
|
point,
|
|
@@ -3687,9 +3679,6 @@ class ResultDataProvider {
|
|
|
3687
3679
|
testCaseRevision: iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseRevision,
|
|
3688
3680
|
});
|
|
3689
3681
|
map[key] = iterationItem;
|
|
3690
|
-
if (isTestReporter && (iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.iteration)) {
|
|
3691
|
-
logger_1.default.debug(`[RunlessResolver] createIterationsMap: mapped runless testCaseId=${String(iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.testCaseId)} to key=${key}`);
|
|
3692
|
-
}
|
|
3693
3682
|
}
|
|
3694
3683
|
else if ((iterationItem === null || iterationItem === void 0 ? void 0 : iterationItem.iteration) && !isTestReporter) {
|
|
3695
3684
|
const key = this.buildIterationLookupKey({
|
|
@@ -3819,7 +3808,7 @@ class ResultDataProvider {
|
|
|
3819
3808
|
* Fetches result Data for a specific test point
|
|
3820
3809
|
*/
|
|
3821
3810
|
async fetchResultDataBase(projectName, testSuiteId, point, fetchResultMethod, createResponseObject, additionalArgs = []) {
|
|
3822
|
-
var _a
|
|
3811
|
+
var _a;
|
|
3823
3812
|
try {
|
|
3824
3813
|
const { lastRunId, lastResultId } = point;
|
|
3825
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);
|
|
@@ -3844,7 +3833,6 @@ class ResultDataProvider {
|
|
|
3844
3833
|
});
|
|
3845
3834
|
}
|
|
3846
3835
|
const stepsList = await this.testStepParserHelper.parseTestSteps(resultData.stepsResultXml, sharedStepIdToRevisionLookupMap);
|
|
3847
|
-
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)}`);
|
|
3848
3836
|
sharedStepIdToRevisionLookupMap.clear();
|
|
3849
3837
|
const stepMap = new Map();
|
|
3850
3838
|
for (const step of stepsList) {
|
|
@@ -3864,7 +3852,6 @@ class ResultDataProvider {
|
|
|
3864
3852
|
iteration.actionResults = actionResults
|
|
3865
3853
|
.filter((result) => result.stepPosition)
|
|
3866
3854
|
.sort((a, b) => this.compareActionResults(a.stepPosition, b.stepPosition));
|
|
3867
|
-
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)`);
|
|
3868
3855
|
}
|
|
3869
3856
|
else {
|
|
3870
3857
|
// Fallback for runs that have no action results: emit test definition steps as Not Run.
|
|
@@ -3884,7 +3871,6 @@ class ResultDataProvider {
|
|
|
3884
3871
|
});
|
|
3885
3872
|
})
|
|
3886
3873
|
.sort((a, b) => this.compareActionResults(a.stepPosition, b.stepPosition));
|
|
3887
|
-
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)`);
|
|
3888
3874
|
}
|
|
3889
3875
|
}
|
|
3890
3876
|
return (resultData === null || resultData === void 0 ? void 0 : resultData.testCase)
|