@elisra-devops/docgen-data-provider 1.93.0 → 1.95.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 +23 -0
- package/bin/modules/ResultDataProvider.js +128 -38
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +260 -2
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +206 -53
- package/src/tests/modules/ResultDataProvider.test.ts +366 -2
|
@@ -333,6 +333,21 @@ describe('ResultDataProvider', () => {
|
|
|
333
333
|
testCaseUrl: 'https://dev.azure.com/organization/test-project/_workitems/edit/1',
|
|
334
334
|
});
|
|
335
335
|
});
|
|
336
|
+
|
|
337
|
+
it('should include pointAsOfTimestamp when lastUpdatedDate is available', () => {
|
|
338
|
+
const testPoint = {
|
|
339
|
+
testCaseReference: { id: 1, name: 'Test Case 1' },
|
|
340
|
+
lastUpdatedDate: '2025-01-01T12:34:56Z',
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
const result = (resultDataProvider as any).mapTestPoint(testPoint, mockProjectName);
|
|
344
|
+
|
|
345
|
+
expect(result).toEqual(
|
|
346
|
+
expect.objectContaining({
|
|
347
|
+
pointAsOfTimestamp: '2025-01-01T12:34:56.000Z',
|
|
348
|
+
})
|
|
349
|
+
);
|
|
350
|
+
});
|
|
336
351
|
});
|
|
337
352
|
|
|
338
353
|
describe('calculateGroupResultSummary', () => {
|
|
@@ -679,6 +694,34 @@ describe('ResultDataProvider', () => {
|
|
|
679
694
|
|
|
680
695
|
// Assert
|
|
681
696
|
expect(result).toEqual(mockTestCases.value);
|
|
697
|
+
expect(TFSServices.getItemContent).toHaveBeenCalledWith(
|
|
698
|
+
expect.stringContaining(
|
|
699
|
+
`/_apis/testplan/Plans/${mockTestPlanId}/Suites/${mockSuiteId}/TestCase?witFields=Microsoft.VSTS.TCM.Steps,System.Rev`
|
|
700
|
+
),
|
|
701
|
+
mockToken
|
|
702
|
+
);
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
describe('resolveSuiteTestCaseRevision', () => {
|
|
707
|
+
it('should resolve System.Rev from workItemFields', () => {
|
|
708
|
+
const revision = (resultDataProvider as any).resolveSuiteTestCaseRevision({
|
|
709
|
+
workItem: {
|
|
710
|
+
workItemFields: [{ key: 'System.Rev', value: '12' }],
|
|
711
|
+
},
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
expect(revision).toBe(12);
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
it('should resolve System.Rev case-insensitively from workItem fields map', () => {
|
|
718
|
+
const revision = (resultDataProvider as any).resolveSuiteTestCaseRevision({
|
|
719
|
+
workItem: {
|
|
720
|
+
fields: { 'system.rev': 14 },
|
|
721
|
+
},
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
expect(revision).toBe(14);
|
|
682
725
|
});
|
|
683
726
|
});
|
|
684
727
|
|
|
@@ -837,7 +880,7 @@ describe('ResultDataProvider', () => {
|
|
|
837
880
|
const result = await (resultDataProvider as any).fetchCrossTestPoints(mockProjectName, [1, 2]);
|
|
838
881
|
|
|
839
882
|
expect(TFSServices.getItemContent).toHaveBeenCalledWith(
|
|
840
|
-
'https://example.com/points/2?witFields=Microsoft.VSTS.TCM.Steps&includePointDetails=true',
|
|
883
|
+
'https://example.com/points/2?witFields=Microsoft.VSTS.TCM.Steps,System.Rev&includePointDetails=true',
|
|
841
884
|
mockToken
|
|
842
885
|
);
|
|
843
886
|
expect(result).toHaveLength(2);
|
|
@@ -3862,7 +3905,9 @@ describe('ResultDataProvider', () => {
|
|
|
3862
3905
|
true,
|
|
3863
3906
|
[],
|
|
3864
3907
|
false,
|
|
3865
|
-
point
|
|
3908
|
+
point,
|
|
3909
|
+
false,
|
|
3910
|
+
true
|
|
3866
3911
|
);
|
|
3867
3912
|
|
|
3868
3913
|
expect(TFSServices.getItemContent).toHaveBeenCalledWith(
|
|
@@ -3874,6 +3919,196 @@ describe('ResultDataProvider', () => {
|
|
|
3874
3919
|
expect(res).toEqual(expect.objectContaining({ testCaseRevision: 9 }));
|
|
3875
3920
|
});
|
|
3876
3921
|
|
|
3922
|
+
it('should ignore point asOf timestamp when runless asOf mode is disabled', async () => {
|
|
3923
|
+
const point = {
|
|
3924
|
+
testCaseId: '123',
|
|
3925
|
+
testCaseName: 'TC 123',
|
|
3926
|
+
outcome: 'passed',
|
|
3927
|
+
pointAsOfTimestamp: '2025-01-01T12:34:56Z',
|
|
3928
|
+
suiteTestCase: {
|
|
3929
|
+
workItem: {
|
|
3930
|
+
id: 123,
|
|
3931
|
+
rev: 9,
|
|
3932
|
+
workItemFields: [{ key: 'Microsoft.VSTS.TCM.Steps', value: '<steps></steps>' }],
|
|
3933
|
+
},
|
|
3934
|
+
},
|
|
3935
|
+
testSuite: { id: '1', name: 'Suite' },
|
|
3936
|
+
};
|
|
3937
|
+
|
|
3938
|
+
(TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce({
|
|
3939
|
+
id: 123,
|
|
3940
|
+
rev: 9,
|
|
3941
|
+
fields: {
|
|
3942
|
+
'System.State': 'Active',
|
|
3943
|
+
'System.CreatedDate': '2024-01-01T00:00:00',
|
|
3944
|
+
'Microsoft.VSTS.TCM.Priority': 1,
|
|
3945
|
+
'System.Title': 'Title 123',
|
|
3946
|
+
'Microsoft.VSTS.TCM.Steps': '<steps></steps>',
|
|
3947
|
+
},
|
|
3948
|
+
relations: null,
|
|
3949
|
+
});
|
|
3950
|
+
|
|
3951
|
+
const res = await (resultDataProvider as any).fetchResultDataBasedOnWiBase(
|
|
3952
|
+
mockProjectName,
|
|
3953
|
+
'0',
|
|
3954
|
+
'0',
|
|
3955
|
+
true,
|
|
3956
|
+
[],
|
|
3957
|
+
false,
|
|
3958
|
+
point
|
|
3959
|
+
);
|
|
3960
|
+
|
|
3961
|
+
const calledUrls = (TFSServices.getItemContent as jest.Mock).mock.calls.map((args: any[]) => String(args[0]));
|
|
3962
|
+
expect(calledUrls.some((url: string) => url.includes('/_apis/wit/workItems/123?asOf='))).toBe(false);
|
|
3963
|
+
expect(calledUrls.some((url: string) => url.includes('/_apis/wit/workItems/123/revisions/9'))).toBe(true);
|
|
3964
|
+
expect(res).toEqual(expect.objectContaining({ testCaseRevision: 9 }));
|
|
3965
|
+
});
|
|
3966
|
+
|
|
3967
|
+
it('should fetch no-run test case by asOf timestamp when pointAsOfTimestamp is available', async () => {
|
|
3968
|
+
(TFSServices.getItemContent as jest.Mock).mockReset();
|
|
3969
|
+
const point = {
|
|
3970
|
+
testCaseId: '123',
|
|
3971
|
+
testCaseName: 'TC 123',
|
|
3972
|
+
outcome: 'passed',
|
|
3973
|
+
pointAsOfTimestamp: '2025-01-01T12:34:56Z',
|
|
3974
|
+
suiteTestCase: {
|
|
3975
|
+
workItem: {
|
|
3976
|
+
id: 123,
|
|
3977
|
+
rev: 9,
|
|
3978
|
+
workItemFields: [{ key: 'Microsoft.VSTS.TCM.Steps', value: '<steps></steps>' }],
|
|
3979
|
+
},
|
|
3980
|
+
},
|
|
3981
|
+
testSuite: { id: '1', name: 'Suite' },
|
|
3982
|
+
};
|
|
3983
|
+
|
|
3984
|
+
(TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce({
|
|
3985
|
+
id: 123,
|
|
3986
|
+
rev: 6,
|
|
3987
|
+
fields: {
|
|
3988
|
+
'System.State': 'Active',
|
|
3989
|
+
'System.CreatedDate': '2024-01-01T00:00:00',
|
|
3990
|
+
'Microsoft.VSTS.TCM.Priority': 1,
|
|
3991
|
+
'System.Title': 'Title 123',
|
|
3992
|
+
'Microsoft.VSTS.TCM.Steps': '<steps></steps>',
|
|
3993
|
+
},
|
|
3994
|
+
relations: null,
|
|
3995
|
+
});
|
|
3996
|
+
|
|
3997
|
+
const res = await (resultDataProvider as any).fetchResultDataBasedOnWiBase(
|
|
3998
|
+
mockProjectName,
|
|
3999
|
+
'0',
|
|
4000
|
+
'0',
|
|
4001
|
+
true,
|
|
4002
|
+
[],
|
|
4003
|
+
false,
|
|
4004
|
+
point,
|
|
4005
|
+
false,
|
|
4006
|
+
true
|
|
4007
|
+
);
|
|
4008
|
+
|
|
4009
|
+
const calledUrls = (TFSServices.getItemContent as jest.Mock).mock.calls.map((args: any[]) => String(args[0]));
|
|
4010
|
+
expect(calledUrls.some((url: string) => url.includes('/_apis/wit/workItems/123?asOf='))).toBe(true);
|
|
4011
|
+
expect(calledUrls.some((url: string) => url.includes('/revisions/9'))).toBe(false);
|
|
4012
|
+
expect(res).toEqual(expect.objectContaining({ testCaseRevision: 6 }));
|
|
4013
|
+
});
|
|
4014
|
+
|
|
4015
|
+
it('should fallback to suite revision when asOf fetch fails', async () => {
|
|
4016
|
+
(TFSServices.getItemContent as jest.Mock).mockReset();
|
|
4017
|
+
const point = {
|
|
4018
|
+
testCaseId: '456',
|
|
4019
|
+
testCaseName: 'TC 456',
|
|
4020
|
+
outcome: 'Not Run',
|
|
4021
|
+
pointAsOfTimestamp: '2025-02-01T00:00:00Z',
|
|
4022
|
+
suiteTestCase: {
|
|
4023
|
+
workItem: {
|
|
4024
|
+
id: 456,
|
|
4025
|
+
workItemFields: [{ key: 'System.Rev', value: '11' }],
|
|
4026
|
+
},
|
|
4027
|
+
},
|
|
4028
|
+
testSuite: { id: '1', name: 'Suite' },
|
|
4029
|
+
};
|
|
4030
|
+
|
|
4031
|
+
(TFSServices.getItemContent as jest.Mock)
|
|
4032
|
+
.mockRejectedValueOnce(new Error('asOf failed'))
|
|
4033
|
+
.mockResolvedValueOnce({
|
|
4034
|
+
id: 456,
|
|
4035
|
+
rev: 11,
|
|
4036
|
+
fields: {
|
|
4037
|
+
'System.State': 'Active',
|
|
4038
|
+
'System.CreatedDate': '2024-01-01T00:00:00',
|
|
4039
|
+
'Microsoft.VSTS.TCM.Priority': 1,
|
|
4040
|
+
'System.Title': 'Title 456',
|
|
4041
|
+
'Microsoft.VSTS.TCM.Steps': '<steps></steps>',
|
|
4042
|
+
},
|
|
4043
|
+
relations: [],
|
|
4044
|
+
});
|
|
4045
|
+
|
|
4046
|
+
const res = await (resultDataProvider as any).fetchResultDataBasedOnWiBase(
|
|
4047
|
+
mockProjectName,
|
|
4048
|
+
'0',
|
|
4049
|
+
'0',
|
|
4050
|
+
true,
|
|
4051
|
+
[],
|
|
4052
|
+
false,
|
|
4053
|
+
point,
|
|
4054
|
+
false,
|
|
4055
|
+
true
|
|
4056
|
+
);
|
|
4057
|
+
|
|
4058
|
+
const calledUrls = (TFSServices.getItemContent as jest.Mock).mock.calls.map((args: any[]) => String(args[0]));
|
|
4059
|
+
expect(calledUrls.some((url: string) => url.includes('/_apis/wit/workItems/456?asOf='))).toBe(true);
|
|
4060
|
+
expect(calledUrls.some((url: string) => url.includes('/_apis/wit/workItems/456/revisions/11'))).toBe(true);
|
|
4061
|
+
expect(res).toEqual(expect.objectContaining({ testCaseRevision: 11 }));
|
|
4062
|
+
});
|
|
4063
|
+
|
|
4064
|
+
it('should resolve no-run revision from System.Rev in suite test-case fields', async () => {
|
|
4065
|
+
(TFSServices.getItemContent as jest.Mock).mockReset();
|
|
4066
|
+
const point = {
|
|
4067
|
+
testCaseId: '321',
|
|
4068
|
+
testCaseName: 'TC 321',
|
|
4069
|
+
outcome: 'Not Run',
|
|
4070
|
+
suiteTestCase: {
|
|
4071
|
+
workItem: {
|
|
4072
|
+
id: 321,
|
|
4073
|
+
workItemFields: [
|
|
4074
|
+
{ key: 'System.Rev', value: '13' },
|
|
4075
|
+
{ key: 'Microsoft.VSTS.TCM.Steps', value: '<steps></steps>' },
|
|
4076
|
+
],
|
|
4077
|
+
},
|
|
4078
|
+
},
|
|
4079
|
+
testSuite: { id: '1', name: 'Suite' },
|
|
4080
|
+
};
|
|
4081
|
+
|
|
4082
|
+
(TFSServices.getItemContent as jest.Mock).mockResolvedValueOnce({
|
|
4083
|
+
id: 321,
|
|
4084
|
+
rev: 13,
|
|
4085
|
+
fields: {
|
|
4086
|
+
'System.State': 'Design',
|
|
4087
|
+
'System.CreatedDate': '2024-05-01T00:00:00',
|
|
4088
|
+
'Microsoft.VSTS.TCM.Priority': 1,
|
|
4089
|
+
'System.Title': 'Title 321',
|
|
4090
|
+
'Microsoft.VSTS.TCM.Steps': '<steps></steps>',
|
|
4091
|
+
},
|
|
4092
|
+
relations: [],
|
|
4093
|
+
});
|
|
4094
|
+
|
|
4095
|
+
const res = await (resultDataProvider as any).fetchResultDataBasedOnWiBase(
|
|
4096
|
+
mockProjectName,
|
|
4097
|
+
'0',
|
|
4098
|
+
'0',
|
|
4099
|
+
true,
|
|
4100
|
+
[],
|
|
4101
|
+
false,
|
|
4102
|
+
point
|
|
4103
|
+
);
|
|
4104
|
+
|
|
4105
|
+
expect(TFSServices.getItemContent).toHaveBeenCalledWith(
|
|
4106
|
+
expect.stringContaining('/_apis/wit/workItems/321/revisions/13?$expand=all'),
|
|
4107
|
+
mockToken
|
|
4108
|
+
);
|
|
4109
|
+
expect(res).toEqual(expect.objectContaining({ testCaseRevision: 13 }));
|
|
4110
|
+
});
|
|
4111
|
+
|
|
3877
4112
|
it('should append linked relations and filter testCaseWorkItemField when isTestReporter=true and isQueryMode=false', async () => {
|
|
3878
4113
|
(TFSServices.getItemContent as jest.Mock).mockReset();
|
|
3879
4114
|
|
|
@@ -5045,6 +5280,35 @@ describe('ResultDataProvider', () => {
|
|
|
5045
5280
|
expect(fetchStrategy).not.toHaveBeenCalled();
|
|
5046
5281
|
expect(result).toEqual([]);
|
|
5047
5282
|
});
|
|
5283
|
+
|
|
5284
|
+
it('should keep points without run/result IDs when test reporter mode is enabled', async () => {
|
|
5285
|
+
const testData = [
|
|
5286
|
+
{
|
|
5287
|
+
testSuiteId: 1,
|
|
5288
|
+
testPointsItems: [{ testCaseId: 10, lastRunId: 101, lastResultId: 201 }, { testCaseId: 11 }],
|
|
5289
|
+
},
|
|
5290
|
+
];
|
|
5291
|
+
const fetchStrategy = jest
|
|
5292
|
+
.fn()
|
|
5293
|
+
.mockResolvedValueOnce({ testCaseId: 10 })
|
|
5294
|
+
.mockResolvedValueOnce({ testCaseId: 11 });
|
|
5295
|
+
|
|
5296
|
+
const result = await (resultDataProvider as any).fetchAllResultDataBase(
|
|
5297
|
+
testData,
|
|
5298
|
+
mockProjectName,
|
|
5299
|
+
true,
|
|
5300
|
+
fetchStrategy
|
|
5301
|
+
);
|
|
5302
|
+
|
|
5303
|
+
expect(fetchStrategy).toHaveBeenCalledTimes(2);
|
|
5304
|
+
expect(fetchStrategy).toHaveBeenNthCalledWith(
|
|
5305
|
+
2,
|
|
5306
|
+
mockProjectName,
|
|
5307
|
+
1,
|
|
5308
|
+
expect.objectContaining({ testCaseId: 11 })
|
|
5309
|
+
);
|
|
5310
|
+
expect(result).toEqual([{ testCaseId: 10 }, { testCaseId: 11 }]);
|
|
5311
|
+
});
|
|
5048
5312
|
});
|
|
5049
5313
|
|
|
5050
5314
|
describe('fetchResultDataBase', () => {
|
|
@@ -5071,6 +5335,26 @@ describe('ResultDataProvider', () => {
|
|
|
5071
5335
|
expect(fetchResultMethod).toHaveBeenCalled();
|
|
5072
5336
|
expect(result).toBeDefined();
|
|
5073
5337
|
});
|
|
5338
|
+
|
|
5339
|
+
it('should call fetch method with runId/resultId as 0 when point has no run history', async () => {
|
|
5340
|
+
const point = { testCaseId: 15, lastRunId: undefined, lastResultId: undefined };
|
|
5341
|
+
const fetchResultMethod = jest.fn().mockResolvedValue({
|
|
5342
|
+
testCase: { id: 15, name: 'TC 15' },
|
|
5343
|
+
testSuite: { name: 'S' },
|
|
5344
|
+
iterationDetails: [],
|
|
5345
|
+
});
|
|
5346
|
+
const createResponseObject = jest.fn().mockReturnValue({ id: 15 });
|
|
5347
|
+
|
|
5348
|
+
await (resultDataProvider as any).fetchResultDataBase(
|
|
5349
|
+
mockProjectName,
|
|
5350
|
+
'suite-no-runs',
|
|
5351
|
+
point,
|
|
5352
|
+
fetchResultMethod,
|
|
5353
|
+
createResponseObject
|
|
5354
|
+
);
|
|
5355
|
+
|
|
5356
|
+
expect(fetchResultMethod).toHaveBeenCalledWith(mockProjectName, '0', '0');
|
|
5357
|
+
});
|
|
5074
5358
|
});
|
|
5075
5359
|
|
|
5076
5360
|
describe('getCombinedResultsSummary', () => {
|
|
@@ -5460,6 +5744,86 @@ describe('ResultDataProvider', () => {
|
|
|
5460
5744
|
})
|
|
5461
5745
|
);
|
|
5462
5746
|
});
|
|
5747
|
+
|
|
5748
|
+
it('should return test-level row with empty step fields when suite has no run history', async () => {
|
|
5749
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan 12');
|
|
5750
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([
|
|
5751
|
+
{
|
|
5752
|
+
testSuiteId: 300,
|
|
5753
|
+
suiteId: 300,
|
|
5754
|
+
suiteName: 'suite no runs',
|
|
5755
|
+
parentSuiteId: 100,
|
|
5756
|
+
parentSuiteName: 'Rel3',
|
|
5757
|
+
suitePath: 'Root/Rel3/suite no runs',
|
|
5758
|
+
testGroupName: 'suite no runs',
|
|
5759
|
+
},
|
|
5760
|
+
]);
|
|
5761
|
+
|
|
5762
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
|
|
5763
|
+
{
|
|
5764
|
+
testSuiteId: 300,
|
|
5765
|
+
suiteId: 300,
|
|
5766
|
+
suiteName: 'suite no runs',
|
|
5767
|
+
parentSuiteId: 100,
|
|
5768
|
+
parentSuiteName: 'Rel3',
|
|
5769
|
+
suitePath: 'Root/Rel3/suite no runs',
|
|
5770
|
+
testGroupName: 'suite no runs',
|
|
5771
|
+
testPointsItems: [
|
|
5772
|
+
{
|
|
5773
|
+
testCaseId: 55,
|
|
5774
|
+
testCaseName: 'TC 55',
|
|
5775
|
+
outcome: 'Not Run',
|
|
5776
|
+
testPointId: 9001,
|
|
5777
|
+
lastRunId: undefined,
|
|
5778
|
+
lastResultId: undefined,
|
|
5779
|
+
lastResultDetails: undefined,
|
|
5780
|
+
},
|
|
5781
|
+
],
|
|
5782
|
+
testCasesItems: [
|
|
5783
|
+
{
|
|
5784
|
+
workItem: {
|
|
5785
|
+
id: 55,
|
|
5786
|
+
workItemFields: [{ key: 'System.Rev', value: 4 }],
|
|
5787
|
+
},
|
|
5788
|
+
},
|
|
5789
|
+
],
|
|
5790
|
+
},
|
|
5791
|
+
]);
|
|
5792
|
+
|
|
5793
|
+
jest.spyOn(resultDataProvider as any, 'fetchAllResultDataTestReporter').mockResolvedValueOnce([
|
|
5794
|
+
{
|
|
5795
|
+
testCaseId: 55,
|
|
5796
|
+
testCase: { id: 55, name: 'TC 55' },
|
|
5797
|
+
testSuite: { name: 'suite no runs' },
|
|
5798
|
+
executionDate: '',
|
|
5799
|
+
testCaseResult: { resultMessage: 'Not Run', url: '' },
|
|
5800
|
+
customFields: {},
|
|
5801
|
+
runBy: '',
|
|
5802
|
+
iteration: undefined,
|
|
5803
|
+
lastRunId: undefined,
|
|
5804
|
+
lastResultId: undefined,
|
|
5805
|
+
},
|
|
5806
|
+
]);
|
|
5807
|
+
|
|
5808
|
+
const result = await resultDataProvider.getTestReporterFlatResults(
|
|
5809
|
+
mockTestPlanId,
|
|
5810
|
+
mockProjectName,
|
|
5811
|
+
undefined,
|
|
5812
|
+
[],
|
|
5813
|
+
false
|
|
5814
|
+
);
|
|
5815
|
+
|
|
5816
|
+
expect(result.rows).toHaveLength(1);
|
|
5817
|
+
expect(result.rows[0]).toEqual(
|
|
5818
|
+
expect.objectContaining({
|
|
5819
|
+
testCaseId: 55,
|
|
5820
|
+
testRunId: undefined,
|
|
5821
|
+
testPointId: 9001,
|
|
5822
|
+
stepOutcome: undefined,
|
|
5823
|
+
stepStepIdentifier: '',
|
|
5824
|
+
})
|
|
5825
|
+
);
|
|
5826
|
+
});
|
|
5463
5827
|
});
|
|
5464
5828
|
|
|
5465
5829
|
describe('getCombinedResultsSummary - appendix branches', () => {
|