@elisra-devops/docgen-data-provider 1.84.0 → 1.86.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 +2 -0
- package/bin/modules/ResultDataProvider.js +201 -45
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +269 -0
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +221 -40
- package/src/tests/modules/ResultDataProvider.test.ts +324 -0
|
@@ -1341,6 +1341,81 @@ describe('ResultDataProvider', () => {
|
|
|
1341
1341
|
expect(il).toBe('IL');
|
|
1342
1342
|
});
|
|
1343
1343
|
|
|
1344
|
+
it('should derive responsibility from Area Path alias when System.AreaPath is missing', () => {
|
|
1345
|
+
const esuk = (resultDataProvider as any).deriveMewpResponsibility({
|
|
1346
|
+
'Custom.SAPWBS': '',
|
|
1347
|
+
'Area Path': 'MEWP\\Customer Requirements\\Level 2\\ATP\\ESUK',
|
|
1348
|
+
});
|
|
1349
|
+
const il = (resultDataProvider as any).deriveMewpResponsibility({
|
|
1350
|
+
'Custom.SAPWBS': '',
|
|
1351
|
+
'Area Path': 'MEWP\\Customer Requirements\\Level 2\\ATP',
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
expect(esuk).toBe('ESUK');
|
|
1355
|
+
expect(il).toBe('IL');
|
|
1356
|
+
});
|
|
1357
|
+
|
|
1358
|
+
it('should derive test-case responsibility from testCasesItems area-path fields', async () => {
|
|
1359
|
+
const fetchByIdsSpy = jest
|
|
1360
|
+
.spyOn(resultDataProvider as any, 'fetchWorkItemsByIds')
|
|
1361
|
+
.mockResolvedValue([]);
|
|
1362
|
+
|
|
1363
|
+
const map = await (resultDataProvider as any).buildMewpTestCaseResponsibilityMap(
|
|
1364
|
+
[
|
|
1365
|
+
{
|
|
1366
|
+
testCasesItems: [
|
|
1367
|
+
{
|
|
1368
|
+
workItem: {
|
|
1369
|
+
id: 101,
|
|
1370
|
+
workItemFields: [{ name: 'Area Path', value: 'MEWP\\Customer Requirements\\Level 2\\ATP' }],
|
|
1371
|
+
},
|
|
1372
|
+
},
|
|
1373
|
+
{
|
|
1374
|
+
workItem: {
|
|
1375
|
+
id: 102,
|
|
1376
|
+
workItemFields: [
|
|
1377
|
+
{ referenceName: 'System.AreaPath', value: 'MEWP\\Customer Requirements\\Level 2\\ATP\\ESUK' },
|
|
1378
|
+
],
|
|
1379
|
+
},
|
|
1380
|
+
},
|
|
1381
|
+
],
|
|
1382
|
+
testPointsItems: [],
|
|
1383
|
+
},
|
|
1384
|
+
],
|
|
1385
|
+
mockProjectName
|
|
1386
|
+
);
|
|
1387
|
+
|
|
1388
|
+
expect(map.get(101)).toBe('IL');
|
|
1389
|
+
expect(map.get(102)).toBe('ESUK');
|
|
1390
|
+
expect(fetchByIdsSpy).not.toHaveBeenCalled();
|
|
1391
|
+
});
|
|
1392
|
+
|
|
1393
|
+
it('should derive test-case responsibility from AreaPath even when SAPWBS exists on test-case payload', async () => {
|
|
1394
|
+
jest.spyOn(resultDataProvider as any, 'fetchWorkItemsByIds').mockResolvedValue([]);
|
|
1395
|
+
|
|
1396
|
+
const map = await (resultDataProvider as any).buildMewpTestCaseResponsibilityMap(
|
|
1397
|
+
[
|
|
1398
|
+
{
|
|
1399
|
+
testCasesItems: [
|
|
1400
|
+
{
|
|
1401
|
+
workItem: {
|
|
1402
|
+
id: 201,
|
|
1403
|
+
workItemFields: [
|
|
1404
|
+
{ referenceName: 'Custom.SAPWBS', value: 'ESUK' },
|
|
1405
|
+
{ referenceName: 'System.AreaPath', value: 'MEWP\\Customer Requirements\\Level 2\\ATP' },
|
|
1406
|
+
],
|
|
1407
|
+
},
|
|
1408
|
+
},
|
|
1409
|
+
],
|
|
1410
|
+
testPointsItems: [],
|
|
1411
|
+
},
|
|
1412
|
+
],
|
|
1413
|
+
mockProjectName
|
|
1414
|
+
);
|
|
1415
|
+
|
|
1416
|
+
expect(map.get(201)).toBe('IL');
|
|
1417
|
+
});
|
|
1418
|
+
|
|
1344
1419
|
it('should zip bug rows with L3/L4 pairs and avoid cross-product duplication', () => {
|
|
1345
1420
|
const requirements = [
|
|
1346
1421
|
{
|
|
@@ -1628,6 +1703,78 @@ describe('ResultDataProvider', () => {
|
|
|
1628
1703
|
expect(rows[0]['Bug ID']).toBe(99001);
|
|
1629
1704
|
expect(rows[0]['Bug Responsibility']).toBe('Elisra');
|
|
1630
1705
|
});
|
|
1706
|
+
|
|
1707
|
+
it('should fallback bug responsibility from test case mapping when external bug row is unknown', () => {
|
|
1708
|
+
const requirements = [
|
|
1709
|
+
{
|
|
1710
|
+
requirementId: 'SR5310',
|
|
1711
|
+
baseKey: 'SR5310',
|
|
1712
|
+
title: 'Req 5310',
|
|
1713
|
+
subSystem: 'Power',
|
|
1714
|
+
responsibility: '',
|
|
1715
|
+
linkedTestCaseIds: [101],
|
|
1716
|
+
},
|
|
1717
|
+
];
|
|
1718
|
+
|
|
1719
|
+
const requirementIndex = new Map([
|
|
1720
|
+
[
|
|
1721
|
+
'SR5310',
|
|
1722
|
+
new Map([
|
|
1723
|
+
[
|
|
1724
|
+
101,
|
|
1725
|
+
{
|
|
1726
|
+
passed: 0,
|
|
1727
|
+
failed: 1,
|
|
1728
|
+
notRun: 0,
|
|
1729
|
+
},
|
|
1730
|
+
],
|
|
1731
|
+
]),
|
|
1732
|
+
],
|
|
1733
|
+
]);
|
|
1734
|
+
|
|
1735
|
+
const observedTestCaseIdsByRequirement = new Map<string, Set<number>>([
|
|
1736
|
+
['SR5310', new Set([101])],
|
|
1737
|
+
]);
|
|
1738
|
+
|
|
1739
|
+
const linkedRequirementsByTestCase = new Map([
|
|
1740
|
+
[
|
|
1741
|
+
101,
|
|
1742
|
+
{
|
|
1743
|
+
baseKeys: new Set(['SR5310']),
|
|
1744
|
+
fullCodes: new Set(['SR5310']),
|
|
1745
|
+
bugIds: new Set([10003]),
|
|
1746
|
+
},
|
|
1747
|
+
],
|
|
1748
|
+
]);
|
|
1749
|
+
|
|
1750
|
+
const externalBugsByTestCase = new Map([
|
|
1751
|
+
[
|
|
1752
|
+
101,
|
|
1753
|
+
[
|
|
1754
|
+
{
|
|
1755
|
+
id: 10003,
|
|
1756
|
+
title: 'Bug 10003',
|
|
1757
|
+
responsibility: 'Unknown',
|
|
1758
|
+
requirementBaseKey: 'SR5310',
|
|
1759
|
+
},
|
|
1760
|
+
],
|
|
1761
|
+
],
|
|
1762
|
+
]);
|
|
1763
|
+
|
|
1764
|
+
const rows = (resultDataProvider as any).buildMewpCoverageRows(
|
|
1765
|
+
requirements,
|
|
1766
|
+
requirementIndex,
|
|
1767
|
+
observedTestCaseIdsByRequirement,
|
|
1768
|
+
linkedRequirementsByTestCase,
|
|
1769
|
+
new Map(),
|
|
1770
|
+
externalBugsByTestCase,
|
|
1771
|
+
new Map(),
|
|
1772
|
+
new Map([[101, 'IL']])
|
|
1773
|
+
);
|
|
1774
|
+
|
|
1775
|
+
expect(rows).toHaveLength(1);
|
|
1776
|
+
expect(rows[0]['Bug Responsibility']).toBe('Elisra');
|
|
1777
|
+
});
|
|
1631
1778
|
});
|
|
1632
1779
|
|
|
1633
1780
|
describe('getMewpInternalValidationFlatResults', () => {
|
|
@@ -1839,6 +1986,74 @@ describe('ResultDataProvider', () => {
|
|
|
1839
1986
|
);
|
|
1840
1987
|
});
|
|
1841
1988
|
|
|
1989
|
+
it('should report only base SR when an entire mentioned family is uncovered', async () => {
|
|
1990
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1991
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
1992
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
|
|
1993
|
+
{
|
|
1994
|
+
testPointsItems: [{ testCaseId: 401, testCaseName: 'TC 401 - Family uncovered' }],
|
|
1995
|
+
testCasesItems: [
|
|
1996
|
+
{
|
|
1997
|
+
workItem: {
|
|
1998
|
+
id: 401,
|
|
1999
|
+
workItemFields: [{ key: 'Steps', value: '<steps id=\"mock-steps-tc-401\"></steps>' }],
|
|
2000
|
+
},
|
|
2001
|
+
},
|
|
2002
|
+
],
|
|
2003
|
+
},
|
|
2004
|
+
]);
|
|
2005
|
+
jest.spyOn(resultDataProvider as any, 'fetchMewpL2Requirements').mockResolvedValueOnce([
|
|
2006
|
+
{
|
|
2007
|
+
workItemId: 9001,
|
|
2008
|
+
requirementId: 'SR0054-1',
|
|
2009
|
+
baseKey: 'SR0054',
|
|
2010
|
+
title: 'SR0054 child 1',
|
|
2011
|
+
responsibility: 'ESUK',
|
|
2012
|
+
linkedTestCaseIds: [],
|
|
2013
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
2014
|
+
},
|
|
2015
|
+
{
|
|
2016
|
+
workItemId: 9002,
|
|
2017
|
+
requirementId: 'SR0054-2',
|
|
2018
|
+
baseKey: 'SR0054',
|
|
2019
|
+
title: 'SR0054 child 2',
|
|
2020
|
+
responsibility: 'ESUK',
|
|
2021
|
+
linkedTestCaseIds: [],
|
|
2022
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
2023
|
+
},
|
|
2024
|
+
]);
|
|
2025
|
+
jest.spyOn(resultDataProvider as any, 'buildLinkedRequirementsByTestCase').mockResolvedValueOnce(
|
|
2026
|
+
new Map([[401, { baseKeys: new Set<string>(), fullCodes: new Set<string>() }]])
|
|
2027
|
+
);
|
|
2028
|
+
jest.spyOn((resultDataProvider as any).testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
|
|
2029
|
+
{
|
|
2030
|
+
stepId: '3',
|
|
2031
|
+
stepPosition: '3',
|
|
2032
|
+
action: 'Validate family root',
|
|
2033
|
+
expected: 'SR0054',
|
|
2034
|
+
isSharedStepTitle: false,
|
|
2035
|
+
},
|
|
2036
|
+
]);
|
|
2037
|
+
|
|
2038
|
+
const result = await (resultDataProvider as any).getMewpInternalValidationFlatResults(
|
|
2039
|
+
'123',
|
|
2040
|
+
mockProjectName,
|
|
2041
|
+
[1]
|
|
2042
|
+
);
|
|
2043
|
+
|
|
2044
|
+
expect(result.rows).toHaveLength(1);
|
|
2045
|
+
expect(result.rows[0]).toEqual(
|
|
2046
|
+
expect.objectContaining({
|
|
2047
|
+
'Test Case ID': 401,
|
|
2048
|
+
'Mentioned but Not Linked': 'Step 3: SR0054',
|
|
2049
|
+
'Linked but Not Mentioned': '',
|
|
2050
|
+
'Validation Status': 'Fail',
|
|
2051
|
+
})
|
|
2052
|
+
);
|
|
2053
|
+
expect(String(result.rows[0]['Mentioned but Not Linked'] || '')).not.toContain('SR0054-1');
|
|
2054
|
+
expect(String(result.rows[0]['Mentioned but Not Linked'] || '')).not.toContain('SR0054-2');
|
|
2055
|
+
});
|
|
2056
|
+
|
|
1842
2057
|
it('should not duplicate Direction A discrepancy when same requirement is repeated in multiple steps', async () => {
|
|
1843
2058
|
jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1844
2059
|
jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
@@ -2515,6 +2730,115 @@ describe('ResultDataProvider', () => {
|
|
|
2515
2730
|
});
|
|
2516
2731
|
});
|
|
2517
2732
|
|
|
2733
|
+
describe('buildLinkedRequirementsByTestCase', () => {
|
|
2734
|
+
it('should map linked requirements only for supported test-case requirement relation types', async () => {
|
|
2735
|
+
const requirements = [
|
|
2736
|
+
{
|
|
2737
|
+
workItemId: 7001,
|
|
2738
|
+
requirementId: 'SR0054-1',
|
|
2739
|
+
baseKey: 'SR0054',
|
|
2740
|
+
linkedTestCaseIds: [],
|
|
2741
|
+
},
|
|
2742
|
+
];
|
|
2743
|
+
const testData = [
|
|
2744
|
+
{
|
|
2745
|
+
testCasesItems: [{ workItem: { id: 1001 } }],
|
|
2746
|
+
testPointsItems: [],
|
|
2747
|
+
},
|
|
2748
|
+
];
|
|
2749
|
+
|
|
2750
|
+
const fetchByIdsSpy = jest
|
|
2751
|
+
.spyOn(resultDataProvider as any, 'fetchWorkItemsByIds')
|
|
2752
|
+
.mockImplementation(async (...args: any[]) => {
|
|
2753
|
+
const ids = Array.isArray(args?.[1]) ? args[1] : [];
|
|
2754
|
+
const includeRelations = !!args?.[2];
|
|
2755
|
+
if (includeRelations) {
|
|
2756
|
+
return [
|
|
2757
|
+
{
|
|
2758
|
+
id: 1001,
|
|
2759
|
+
relations: [
|
|
2760
|
+
{
|
|
2761
|
+
rel: 'Microsoft.VSTS.Common.TestedBy-Reverse',
|
|
2762
|
+
url: 'https://dev.azure.com/org/project/_apis/wit/workItems/7001',
|
|
2763
|
+
},
|
|
2764
|
+
{
|
|
2765
|
+
rel: 'System.LinkTypes.Related',
|
|
2766
|
+
url: 'https://dev.azure.com/org/project/_apis/wit/workItems/7001',
|
|
2767
|
+
},
|
|
2768
|
+
],
|
|
2769
|
+
},
|
|
2770
|
+
];
|
|
2771
|
+
}
|
|
2772
|
+
return ids.map((id) => ({
|
|
2773
|
+
id,
|
|
2774
|
+
fields: {
|
|
2775
|
+
'System.WorkItemType': id === 7001 ? 'Requirement' : 'Test Case',
|
|
2776
|
+
},
|
|
2777
|
+
}));
|
|
2778
|
+
});
|
|
2779
|
+
|
|
2780
|
+
const linked = await (resultDataProvider as any).buildLinkedRequirementsByTestCase(
|
|
2781
|
+
requirements,
|
|
2782
|
+
testData,
|
|
2783
|
+
mockProjectName
|
|
2784
|
+
);
|
|
2785
|
+
|
|
2786
|
+
expect(fetchByIdsSpy).toHaveBeenCalled();
|
|
2787
|
+
expect(linked.get(1001)?.baseKeys?.has('SR0054')).toBe(true);
|
|
2788
|
+
expect(linked.get(1001)?.fullCodes?.has('SR0054-1')).toBe(true);
|
|
2789
|
+
});
|
|
2790
|
+
|
|
2791
|
+
it('should ignore unsupported relation types when linking test case to requirements', async () => {
|
|
2792
|
+
const requirements = [
|
|
2793
|
+
{
|
|
2794
|
+
workItemId: 7002,
|
|
2795
|
+
requirementId: 'SR0099-1',
|
|
2796
|
+
baseKey: 'SR0099',
|
|
2797
|
+
linkedTestCaseIds: [],
|
|
2798
|
+
},
|
|
2799
|
+
];
|
|
2800
|
+
const testData = [
|
|
2801
|
+
{
|
|
2802
|
+
testCasesItems: [{ workItem: { id: 1002 } }],
|
|
2803
|
+
testPointsItems: [],
|
|
2804
|
+
},
|
|
2805
|
+
];
|
|
2806
|
+
|
|
2807
|
+
jest.spyOn(resultDataProvider as any, 'fetchWorkItemsByIds').mockImplementation(async (...args: any[]) => {
|
|
2808
|
+
const ids = Array.isArray(args?.[1]) ? args[1] : [];
|
|
2809
|
+
const includeRelations = !!args?.[2];
|
|
2810
|
+
if (includeRelations) {
|
|
2811
|
+
return [
|
|
2812
|
+
{
|
|
2813
|
+
id: 1002,
|
|
2814
|
+
relations: [
|
|
2815
|
+
{
|
|
2816
|
+
rel: 'System.LinkTypes.Related',
|
|
2817
|
+
url: 'https://dev.azure.com/org/project/_apis/wit/workItems/7002',
|
|
2818
|
+
},
|
|
2819
|
+
],
|
|
2820
|
+
},
|
|
2821
|
+
];
|
|
2822
|
+
}
|
|
2823
|
+
return ids.map((id) => ({
|
|
2824
|
+
id,
|
|
2825
|
+
fields: {
|
|
2826
|
+
'System.WorkItemType': id === 7002 ? 'Requirement' : 'Test Case',
|
|
2827
|
+
},
|
|
2828
|
+
}));
|
|
2829
|
+
});
|
|
2830
|
+
|
|
2831
|
+
const linked = await (resultDataProvider as any).buildLinkedRequirementsByTestCase(
|
|
2832
|
+
requirements,
|
|
2833
|
+
testData,
|
|
2834
|
+
mockProjectName
|
|
2835
|
+
);
|
|
2836
|
+
|
|
2837
|
+
expect(linked.get(1002)?.baseKeys?.has('SR0099')).toBe(false);
|
|
2838
|
+
expect(linked.get(1002)?.fullCodes?.has('SR0099-1')).toBe(false);
|
|
2839
|
+
});
|
|
2840
|
+
});
|
|
2841
|
+
|
|
2518
2842
|
describe('MEWP rel fallback scoping', () => {
|
|
2519
2843
|
it('should fallback to previous Rel run when latest selected Rel has no run for a test case', async () => {
|
|
2520
2844
|
const suites = [
|