@elisra-devops/docgen-data-provider 1.93.0 → 1.94.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 +1 -0
- package/bin/modules/ResultDataProvider.js +26 -8
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +146 -1
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +22 -2
- package/src/tests/modules/ResultDataProvider.test.ts +205 -1
package/package.json
CHANGED
|
@@ -3049,7 +3049,7 @@ export default class ResultDataProvider {
|
|
|
3049
3049
|
// Fetch detailed information for each test point and map to required format
|
|
3050
3050
|
const detailedPoints = await Promise.all(
|
|
3051
3051
|
latestPoints.map(async (point: any) => {
|
|
3052
|
-
const url = `${point.url}?witFields=Microsoft.VSTS.TCM.Steps&includePointDetails=true`;
|
|
3052
|
+
const url = `${point.url}?witFields=Microsoft.VSTS.TCM.Steps,System.Rev&includePointDetails=true`;
|
|
3053
3053
|
const detailedPoint = await TFSServices.getItemContent(url, this.token);
|
|
3054
3054
|
return this.mapTestPointForCrossPlans(detailedPoint, projectName);
|
|
3055
3055
|
// return this.mapTestPointForCrossPlans(detailedPoint, projectName);
|
|
@@ -3142,7 +3142,7 @@ export default class ResultDataProvider {
|
|
|
3142
3142
|
testPlanId: string,
|
|
3143
3143
|
suiteId: string
|
|
3144
3144
|
): Promise<any[]> {
|
|
3145
|
-
const url = `${this.orgUrl}${projectName}/_apis/testplan/Plans/${testPlanId}/Suites/${suiteId}/TestCase?witFields=Microsoft.VSTS.TCM.Steps`;
|
|
3145
|
+
const url = `${this.orgUrl}${projectName}/_apis/testplan/Plans/${testPlanId}/Suites/${suiteId}/TestCase?witFields=Microsoft.VSTS.TCM.Steps,System.Rev`;
|
|
3146
3146
|
|
|
3147
3147
|
const { value: testCases } = await TFSServices.getItemContent(url, this.token);
|
|
3148
3148
|
|
|
@@ -3186,8 +3186,28 @@ export default class ResultDataProvider {
|
|
|
3186
3186
|
return fields;
|
|
3187
3187
|
}
|
|
3188
3188
|
|
|
3189
|
+
private getFieldValueByName(fields: Record<string, any>, fieldName: string): any {
|
|
3190
|
+
if (!fields || typeof fields !== 'object') return undefined;
|
|
3191
|
+
if (Object.prototype.hasOwnProperty.call(fields, fieldName)) {
|
|
3192
|
+
return fields[fieldName];
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3195
|
+
const lookupName = String(fieldName || '').toLowerCase().trim();
|
|
3196
|
+
if (!lookupName) return undefined;
|
|
3197
|
+
const matchedKey = Object.keys(fields).find(
|
|
3198
|
+
(key) => String(key || '').toLowerCase().trim() === lookupName
|
|
3199
|
+
);
|
|
3200
|
+
return matchedKey ? fields[matchedKey] : undefined;
|
|
3201
|
+
}
|
|
3202
|
+
|
|
3189
3203
|
private resolveSuiteTestCaseRevision(testCaseItem: any): number {
|
|
3204
|
+
const fieldsFromList = this.extractWorkItemFieldsMap(testCaseItem?.workItem?.workItemFields);
|
|
3205
|
+
const fieldsFromMap = testCaseItem?.workItem?.fields || {};
|
|
3206
|
+
const systemRevFromList = this.getFieldValueByName(fieldsFromList, 'System.Rev');
|
|
3207
|
+
const systemRevFromMap = this.getFieldValueByName(fieldsFromMap, 'System.Rev');
|
|
3190
3208
|
const revisionCandidates = [
|
|
3209
|
+
systemRevFromList,
|
|
3210
|
+
systemRevFromMap,
|
|
3191
3211
|
testCaseItem?.workItem?.rev,
|
|
3192
3212
|
testCaseItem?.workItem?.revision,
|
|
3193
3213
|
testCaseItem?.workItem?.version,
|
|
@@ -679,6 +679,34 @@ describe('ResultDataProvider', () => {
|
|
|
679
679
|
|
|
680
680
|
// Assert
|
|
681
681
|
expect(result).toEqual(mockTestCases.value);
|
|
682
|
+
expect(TFSServices.getItemContent).toHaveBeenCalledWith(
|
|
683
|
+
expect.stringContaining(
|
|
684
|
+
`/_apis/testplan/Plans/${mockTestPlanId}/Suites/${mockSuiteId}/TestCase?witFields=Microsoft.VSTS.TCM.Steps,System.Rev`
|
|
685
|
+
),
|
|
686
|
+
mockToken
|
|
687
|
+
);
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
describe('resolveSuiteTestCaseRevision', () => {
|
|
692
|
+
it('should resolve System.Rev from workItemFields', () => {
|
|
693
|
+
const revision = (resultDataProvider as any).resolveSuiteTestCaseRevision({
|
|
694
|
+
workItem: {
|
|
695
|
+
workItemFields: [{ key: 'System.Rev', value: '12' }],
|
|
696
|
+
},
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
expect(revision).toBe(12);
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
it('should resolve System.Rev case-insensitively from workItem fields map', () => {
|
|
703
|
+
const revision = (resultDataProvider as any).resolveSuiteTestCaseRevision({
|
|
704
|
+
workItem: {
|
|
705
|
+
fields: { 'system.rev': 14 },
|
|
706
|
+
},
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
expect(revision).toBe(14);
|
|
682
710
|
});
|
|
683
711
|
});
|
|
684
712
|
|
|
@@ -837,7 +865,7 @@ describe('ResultDataProvider', () => {
|
|
|
837
865
|
const result = await (resultDataProvider as any).fetchCrossTestPoints(mockProjectName, [1, 2]);
|
|
838
866
|
|
|
839
867
|
expect(TFSServices.getItemContent).toHaveBeenCalledWith(
|
|
840
|
-
'https://example.com/points/2?witFields=Microsoft.VSTS.TCM.Steps&includePointDetails=true',
|
|
868
|
+
'https://example.com/points/2?witFields=Microsoft.VSTS.TCM.Steps,System.Rev&includePointDetails=true',
|
|
841
869
|
mockToken
|
|
842
870
|
);
|
|
843
871
|
expect(result).toHaveLength(2);
|
|
@@ -3874,6 +3902,53 @@ describe('ResultDataProvider', () => {
|
|
|
3874
3902
|
expect(res).toEqual(expect.objectContaining({ testCaseRevision: 9 }));
|
|
3875
3903
|
});
|
|
3876
3904
|
|
|
3905
|
+
it('should resolve no-run revision from System.Rev in suite test-case fields', async () => {
|
|
3906
|
+
const point = {
|
|
3907
|
+
testCaseId: '321',
|
|
3908
|
+
testCaseName: 'TC 321',
|
|
3909
|
+
outcome: 'Not Run',
|
|
3910
|
+
suiteTestCase: {
|
|
3911
|
+
workItem: {
|
|
3912
|
+
id: 321,
|
|
3913
|
+
workItemFields: [
|
|
3914
|
+
{ key: 'System.Rev', value: '13' },
|
|
3915
|
+
{ key: 'Microsoft.VSTS.TCM.Steps', value: '<steps></steps>' },
|
|
3916
|
+
],
|
|
3917
|
+
},
|
|
3918
|
+
},
|
|
3919
|
+
testSuite: { id: '1', name: 'Suite' },
|
|
3920
|
+
};
|
|
3921
|
+
|
|
3922
|
+
(TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce({
|
|
3923
|
+
id: 321,
|
|
3924
|
+
rev: 13,
|
|
3925
|
+
fields: {
|
|
3926
|
+
'System.State': 'Design',
|
|
3927
|
+
'System.CreatedDate': '2024-05-01T00:00:00',
|
|
3928
|
+
'Microsoft.VSTS.TCM.Priority': 1,
|
|
3929
|
+
'System.Title': 'Title 321',
|
|
3930
|
+
'Microsoft.VSTS.TCM.Steps': '<steps></steps>',
|
|
3931
|
+
},
|
|
3932
|
+
relations: [],
|
|
3933
|
+
});
|
|
3934
|
+
|
|
3935
|
+
const res = await (resultDataProvider as any).fetchResultDataBasedOnWiBase(
|
|
3936
|
+
mockProjectName,
|
|
3937
|
+
'0',
|
|
3938
|
+
'0',
|
|
3939
|
+
true,
|
|
3940
|
+
[],
|
|
3941
|
+
false,
|
|
3942
|
+
point
|
|
3943
|
+
);
|
|
3944
|
+
|
|
3945
|
+
expect(TFSServices.getItemContent).toHaveBeenCalledWith(
|
|
3946
|
+
expect.stringContaining('/_apis/wit/workItems/321/revisions/13?$expand=all'),
|
|
3947
|
+
mockToken
|
|
3948
|
+
);
|
|
3949
|
+
expect(res).toEqual(expect.objectContaining({ testCaseRevision: 13 }));
|
|
3950
|
+
});
|
|
3951
|
+
|
|
3877
3952
|
it('should append linked relations and filter testCaseWorkItemField when isTestReporter=true and isQueryMode=false', async () => {
|
|
3878
3953
|
(TFSServices.getItemContent as jest.Mock).mockReset();
|
|
3879
3954
|
|
|
@@ -5045,6 +5120,35 @@ describe('ResultDataProvider', () => {
|
|
|
5045
5120
|
expect(fetchStrategy).not.toHaveBeenCalled();
|
|
5046
5121
|
expect(result).toEqual([]);
|
|
5047
5122
|
});
|
|
5123
|
+
|
|
5124
|
+
it('should keep points without run/result IDs when test reporter mode is enabled', async () => {
|
|
5125
|
+
const testData = [
|
|
5126
|
+
{
|
|
5127
|
+
testSuiteId: 1,
|
|
5128
|
+
testPointsItems: [{ testCaseId: 10, lastRunId: 101, lastResultId: 201 }, { testCaseId: 11 }],
|
|
5129
|
+
},
|
|
5130
|
+
];
|
|
5131
|
+
const fetchStrategy = jest
|
|
5132
|
+
.fn()
|
|
5133
|
+
.mockResolvedValueOnce({ testCaseId: 10 })
|
|
5134
|
+
.mockResolvedValueOnce({ testCaseId: 11 });
|
|
5135
|
+
|
|
5136
|
+
const result = await (resultDataProvider as any).fetchAllResultDataBase(
|
|
5137
|
+
testData,
|
|
5138
|
+
mockProjectName,
|
|
5139
|
+
true,
|
|
5140
|
+
fetchStrategy
|
|
5141
|
+
);
|
|
5142
|
+
|
|
5143
|
+
expect(fetchStrategy).toHaveBeenCalledTimes(2);
|
|
5144
|
+
expect(fetchStrategy).toHaveBeenNthCalledWith(
|
|
5145
|
+
2,
|
|
5146
|
+
mockProjectName,
|
|
5147
|
+
1,
|
|
5148
|
+
expect.objectContaining({ testCaseId: 11 })
|
|
5149
|
+
);
|
|
5150
|
+
expect(result).toEqual([{ testCaseId: 10 }, { testCaseId: 11 }]);
|
|
5151
|
+
});
|
|
5048
5152
|
});
|
|
5049
5153
|
|
|
5050
5154
|
describe('fetchResultDataBase', () => {
|
|
@@ -5071,6 +5175,26 @@ describe('ResultDataProvider', () => {
|
|
|
5071
5175
|
expect(fetchResultMethod).toHaveBeenCalled();
|
|
5072
5176
|
expect(result).toBeDefined();
|
|
5073
5177
|
});
|
|
5178
|
+
|
|
5179
|
+
it('should call fetch method with runId/resultId as 0 when point has no run history', async () => {
|
|
5180
|
+
const point = { testCaseId: 15, lastRunId: undefined, lastResultId: undefined };
|
|
5181
|
+
const fetchResultMethod = jest.fn().mockResolvedValue({
|
|
5182
|
+
testCase: { id: 15, name: 'TC 15' },
|
|
5183
|
+
testSuite: { name: 'S' },
|
|
5184
|
+
iterationDetails: [],
|
|
5185
|
+
});
|
|
5186
|
+
const createResponseObject = jest.fn().mockReturnValue({ id: 15 });
|
|
5187
|
+
|
|
5188
|
+
await (resultDataProvider as any).fetchResultDataBase(
|
|
5189
|
+
mockProjectName,
|
|
5190
|
+
'suite-no-runs',
|
|
5191
|
+
point,
|
|
5192
|
+
fetchResultMethod,
|
|
5193
|
+
createResponseObject
|
|
5194
|
+
);
|
|
5195
|
+
|
|
5196
|
+
expect(fetchResultMethod).toHaveBeenCalledWith(mockProjectName, '0', '0');
|
|
5197
|
+
});
|
|
5074
5198
|
});
|
|
5075
5199
|
|
|
5076
5200
|
describe('getCombinedResultsSummary', () => {
|
|
@@ -5460,6 +5584,86 @@ describe('ResultDataProvider', () => {
|
|
|
5460
5584
|
})
|
|
5461
5585
|
);
|
|
5462
5586
|
});
|
|
5587
|
+
|
|
5588
|
+
it('should return test-level row with empty step fields when suite has no run history', async () => {
|
|
5589
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan 12');
|
|
5590
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([
|
|
5591
|
+
{
|
|
5592
|
+
testSuiteId: 300,
|
|
5593
|
+
suiteId: 300,
|
|
5594
|
+
suiteName: 'suite no runs',
|
|
5595
|
+
parentSuiteId: 100,
|
|
5596
|
+
parentSuiteName: 'Rel3',
|
|
5597
|
+
suitePath: 'Root/Rel3/suite no runs',
|
|
5598
|
+
testGroupName: 'suite no runs',
|
|
5599
|
+
},
|
|
5600
|
+
]);
|
|
5601
|
+
|
|
5602
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
|
|
5603
|
+
{
|
|
5604
|
+
testSuiteId: 300,
|
|
5605
|
+
suiteId: 300,
|
|
5606
|
+
suiteName: 'suite no runs',
|
|
5607
|
+
parentSuiteId: 100,
|
|
5608
|
+
parentSuiteName: 'Rel3',
|
|
5609
|
+
suitePath: 'Root/Rel3/suite no runs',
|
|
5610
|
+
testGroupName: 'suite no runs',
|
|
5611
|
+
testPointsItems: [
|
|
5612
|
+
{
|
|
5613
|
+
testCaseId: 55,
|
|
5614
|
+
testCaseName: 'TC 55',
|
|
5615
|
+
outcome: 'Not Run',
|
|
5616
|
+
testPointId: 9001,
|
|
5617
|
+
lastRunId: undefined,
|
|
5618
|
+
lastResultId: undefined,
|
|
5619
|
+
lastResultDetails: undefined,
|
|
5620
|
+
},
|
|
5621
|
+
],
|
|
5622
|
+
testCasesItems: [
|
|
5623
|
+
{
|
|
5624
|
+
workItem: {
|
|
5625
|
+
id: 55,
|
|
5626
|
+
workItemFields: [{ key: 'System.Rev', value: 4 }],
|
|
5627
|
+
},
|
|
5628
|
+
},
|
|
5629
|
+
],
|
|
5630
|
+
},
|
|
5631
|
+
]);
|
|
5632
|
+
|
|
5633
|
+
jest.spyOn(resultDataProvider as any, 'fetchAllResultDataTestReporter').mockResolvedValueOnce([
|
|
5634
|
+
{
|
|
5635
|
+
testCaseId: 55,
|
|
5636
|
+
testCase: { id: 55, name: 'TC 55' },
|
|
5637
|
+
testSuite: { name: 'suite no runs' },
|
|
5638
|
+
executionDate: '',
|
|
5639
|
+
testCaseResult: { resultMessage: 'Not Run', url: '' },
|
|
5640
|
+
customFields: {},
|
|
5641
|
+
runBy: '',
|
|
5642
|
+
iteration: undefined,
|
|
5643
|
+
lastRunId: undefined,
|
|
5644
|
+
lastResultId: undefined,
|
|
5645
|
+
},
|
|
5646
|
+
]);
|
|
5647
|
+
|
|
5648
|
+
const result = await resultDataProvider.getTestReporterFlatResults(
|
|
5649
|
+
mockTestPlanId,
|
|
5650
|
+
mockProjectName,
|
|
5651
|
+
undefined,
|
|
5652
|
+
[],
|
|
5653
|
+
false
|
|
5654
|
+
);
|
|
5655
|
+
|
|
5656
|
+
expect(result.rows).toHaveLength(1);
|
|
5657
|
+
expect(result.rows[0]).toEqual(
|
|
5658
|
+
expect.objectContaining({
|
|
5659
|
+
testCaseId: 55,
|
|
5660
|
+
testRunId: undefined,
|
|
5661
|
+
testPointId: 9001,
|
|
5662
|
+
stepOutcome: undefined,
|
|
5663
|
+
stepStepIdentifier: '',
|
|
5664
|
+
})
|
|
5665
|
+
);
|
|
5666
|
+
});
|
|
5463
5667
|
});
|
|
5464
5668
|
|
|
5465
5669
|
describe('getCombinedResultsSummary - appendix branches', () => {
|