@elisra-devops/docgen-data-provider 1.101.0 → 1.103.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/models/mewp-reporting.d.ts +5 -0
- package/bin/modules/ResultDataProvider.d.ts +34 -0
- package/bin/modules/ResultDataProvider.js +213 -90
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +335 -1
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/models/mewp-reporting.ts +5 -0
- package/src/modules/ResultDataProvider.ts +229 -115
- package/src/tests/modules/ResultDataProvider.test.ts +389 -1
|
@@ -894,6 +894,44 @@ describe('ResultDataProvider', () => {
|
|
|
894
894
|
});
|
|
895
895
|
});
|
|
896
896
|
describe('getMewpL2CoverageFlatResults', () => {
|
|
897
|
+
it('should split SR prefix into SR # + L2 REQ Title while preserving full title', () => {
|
|
898
|
+
const row = resultDataProvider.createMewpCoverageRow({
|
|
899
|
+
workItemId: 5054,
|
|
900
|
+
requirementId: 'SR0054',
|
|
901
|
+
title: 'SR0054 - Engine startup coverage',
|
|
902
|
+
owner: 'ESUK',
|
|
903
|
+
subSystem: 'Propulsion',
|
|
904
|
+
responsibility: 'ESUK',
|
|
905
|
+
}, 'Pass', { id: '', title: '', responsibility: '' }, { l3Id: '', l3Title: '', l4Id: '', l4Title: '' });
|
|
906
|
+
expect(row).toEqual(expect.objectContaining({
|
|
907
|
+
'L2 REQ ID': '5054',
|
|
908
|
+
'SR #': 'SR0054',
|
|
909
|
+
'L2 REQ Title': 'Engine startup coverage',
|
|
910
|
+
'L2 REQ Full Title': 'SR0054 - Engine startup coverage',
|
|
911
|
+
'L2 Owner': 'ESUK',
|
|
912
|
+
'L2 SubSystem': 'Propulsion',
|
|
913
|
+
}));
|
|
914
|
+
});
|
|
915
|
+
it('should keep full title when title is only the SR token', () => {
|
|
916
|
+
const row = resultDataProvider.createMewpCoverageRow({
|
|
917
|
+
workItemId: 9999,
|
|
918
|
+
requirementId: 'SR9999',
|
|
919
|
+
title: 'SR9999',
|
|
920
|
+
owner: 'IL',
|
|
921
|
+
subSystem: '',
|
|
922
|
+
responsibility: 'IL',
|
|
923
|
+
}, 'Not Run', { id: '', title: '', responsibility: '' }, { l3Id: '', l3Title: '', l4Id: '', l4Title: '' });
|
|
924
|
+
expect(row['L2 REQ Title']).toBe('SR9999');
|
|
925
|
+
expect(row['L2 REQ Full Title']).toBe('SR9999');
|
|
926
|
+
expect(row['L2 Owner']).toBe('IL');
|
|
927
|
+
});
|
|
928
|
+
it('should resolve L2 run status precedence: Fail > Not Run > Pass', () => {
|
|
929
|
+
const resolve = resultDataProvider.resolveMewpL2RunStatus.bind(resultDataProvider);
|
|
930
|
+
expect(resolve({ passed: 2, failed: 1, notRun: 3, hasAnyTestCase: true })).toBe('Fail');
|
|
931
|
+
expect(resolve({ passed: 5, failed: 0, notRun: 1, hasAnyTestCase: true })).toBe('Not Run');
|
|
932
|
+
expect(resolve({ passed: 1, failed: 0, notRun: 0, hasAnyTestCase: true })).toBe('Pass');
|
|
933
|
+
expect(resolve({ passed: 0, failed: 0, notRun: 0, hasAnyTestCase: true })).toBe('Not Run');
|
|
934
|
+
});
|
|
897
935
|
it('should fetch MEWP scoped test data from selected suites', async () => {
|
|
898
936
|
jest.spyOn(resultDataProvider, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
899
937
|
const scopedSpy = jest
|
|
@@ -987,7 +1025,7 @@ describe('ResultDataProvider', () => {
|
|
|
987
1025
|
const result = await resultDataProvider.getMewpL2CoverageFlatResults('123', mockProjectName, [1]);
|
|
988
1026
|
expect(result).toEqual(expect.objectContaining({
|
|
989
1027
|
sheetName: expect.stringContaining('MEWP L2 Coverage'),
|
|
990
|
-
columnOrder: expect.arrayContaining(['L2 REQ ID', 'L2 REQ Title', 'L2 Run Status']),
|
|
1028
|
+
columnOrder: expect.arrayContaining(['L2 REQ ID', 'SR #', 'L2 REQ Title', 'L2 Owner', 'L2 Run Status']),
|
|
991
1029
|
}));
|
|
992
1030
|
const covered = result.rows.find((row) => row['L2 REQ ID'] === '5001');
|
|
993
1031
|
const inferredByStepText = result.rows.find((row) => row['L2 REQ ID'] === '5002');
|
|
@@ -1586,6 +1624,302 @@ describe('ResultDataProvider', () => {
|
|
|
1586
1624
|
'Validation Status': 'Fail',
|
|
1587
1625
|
}));
|
|
1588
1626
|
});
|
|
1627
|
+
it('should parse requirement mentions only from the assumptions section in test-case description', async () => {
|
|
1628
|
+
jest.spyOn(resultDataProvider, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1629
|
+
jest.spyOn(resultDataProvider, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
1630
|
+
jest.spyOn(resultDataProvider, 'fetchTestData').mockResolvedValueOnce([
|
|
1631
|
+
{
|
|
1632
|
+
testPointsItems: [{ testCaseId: 121, testCaseName: 'TC 121' }],
|
|
1633
|
+
testCasesItems: [
|
|
1634
|
+
{
|
|
1635
|
+
workItem: {
|
|
1636
|
+
id: 121,
|
|
1637
|
+
workItemFields: [
|
|
1638
|
+
{ key: 'Steps', value: '<steps></steps>' },
|
|
1639
|
+
{
|
|
1640
|
+
key: 'System.Description',
|
|
1641
|
+
value: `
|
|
1642
|
+
<p>Some intro text</p>
|
|
1643
|
+
<b><u>Trial specific assumptions, constraints, dependencies and requirements</u></b>
|
|
1644
|
+
<p>- VVRM-1 & SR0100 - some text 1</p>
|
|
1645
|
+
<p>- VVRM-3 & SR0588 - some text 2</p>
|
|
1646
|
+
<p>- SR1234, SR5678, SR1212</p>
|
|
1647
|
+
<p>some other text</p>
|
|
1648
|
+
<u><b>another title</b></u>
|
|
1649
|
+
<p>SR2242</p>
|
|
1650
|
+
`,
|
|
1651
|
+
},
|
|
1652
|
+
],
|
|
1653
|
+
},
|
|
1654
|
+
},
|
|
1655
|
+
],
|
|
1656
|
+
},
|
|
1657
|
+
]);
|
|
1658
|
+
jest.spyOn(resultDataProvider, 'fetchMewpL2Requirements').mockResolvedValueOnce([
|
|
1659
|
+
{
|
|
1660
|
+
workItemId: 8100,
|
|
1661
|
+
requirementId: 'SR0100',
|
|
1662
|
+
baseKey: 'SR0100',
|
|
1663
|
+
title: 'Req 100',
|
|
1664
|
+
responsibility: 'ESUK',
|
|
1665
|
+
linkedTestCaseIds: [],
|
|
1666
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
workItemId: 8588,
|
|
1670
|
+
requirementId: 'SR0588',
|
|
1671
|
+
baseKey: 'SR0588',
|
|
1672
|
+
title: 'Req 588',
|
|
1673
|
+
responsibility: 'ESUK',
|
|
1674
|
+
linkedTestCaseIds: [],
|
|
1675
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1676
|
+
},
|
|
1677
|
+
{
|
|
1678
|
+
workItemId: 91234,
|
|
1679
|
+
requirementId: 'SR1234',
|
|
1680
|
+
baseKey: 'SR1234',
|
|
1681
|
+
title: 'Req 1234',
|
|
1682
|
+
responsibility: 'ESUK',
|
|
1683
|
+
linkedTestCaseIds: [],
|
|
1684
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1685
|
+
},
|
|
1686
|
+
{
|
|
1687
|
+
workItemId: 95678,
|
|
1688
|
+
requirementId: 'SR5678',
|
|
1689
|
+
baseKey: 'SR5678',
|
|
1690
|
+
title: 'Req 5678',
|
|
1691
|
+
responsibility: 'ESUK',
|
|
1692
|
+
linkedTestCaseIds: [],
|
|
1693
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1694
|
+
},
|
|
1695
|
+
{
|
|
1696
|
+
workItemId: 91212,
|
|
1697
|
+
requirementId: 'SR1212',
|
|
1698
|
+
baseKey: 'SR1212',
|
|
1699
|
+
title: 'Req 1212',
|
|
1700
|
+
responsibility: 'ESUK',
|
|
1701
|
+
linkedTestCaseIds: [],
|
|
1702
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1703
|
+
},
|
|
1704
|
+
{
|
|
1705
|
+
workItemId: 92242,
|
|
1706
|
+
requirementId: 'SR2242',
|
|
1707
|
+
baseKey: 'SR2242',
|
|
1708
|
+
title: 'Req 2242',
|
|
1709
|
+
responsibility: 'ESUK',
|
|
1710
|
+
linkedTestCaseIds: [],
|
|
1711
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1712
|
+
},
|
|
1713
|
+
]);
|
|
1714
|
+
jest
|
|
1715
|
+
.spyOn(resultDataProvider, 'buildLinkedRequirementsByTestCase')
|
|
1716
|
+
.mockResolvedValueOnce(new Map([[121, { baseKeys: new Set(), fullCodes: new Set() }]]));
|
|
1717
|
+
jest.spyOn(resultDataProvider.testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
|
|
1718
|
+
{
|
|
1719
|
+
stepId: '1',
|
|
1720
|
+
stepPosition: '1',
|
|
1721
|
+
action: '',
|
|
1722
|
+
expected: '',
|
|
1723
|
+
isSharedStepTitle: false,
|
|
1724
|
+
},
|
|
1725
|
+
]);
|
|
1726
|
+
const result = await resultDataProvider.getMewpInternalValidationFlatResults('123', mockProjectName, [1]);
|
|
1727
|
+
expect(result.rows).toHaveLength(1);
|
|
1728
|
+
const directionA = String(result.rows[0]['Mentioned but Not Linked'] || '');
|
|
1729
|
+
expect(directionA).toContain('Assumptions:');
|
|
1730
|
+
expect(directionA).toContain('SR0100');
|
|
1731
|
+
expect(directionA).toContain('SR0588');
|
|
1732
|
+
expect(directionA).toContain('SR1234');
|
|
1733
|
+
expect(directionA).toContain('SR5678');
|
|
1734
|
+
expect(directionA).toContain('SR1212');
|
|
1735
|
+
expect(directionA).not.toContain('SR2242');
|
|
1736
|
+
expect(result.rows[0]).toEqual(expect.objectContaining({
|
|
1737
|
+
'Validation Status': 'Fail',
|
|
1738
|
+
}));
|
|
1739
|
+
});
|
|
1740
|
+
it('should detect assumptions heading case-insensitively in description', async () => {
|
|
1741
|
+
jest.spyOn(resultDataProvider, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1742
|
+
jest.spyOn(resultDataProvider, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
1743
|
+
jest.spyOn(resultDataProvider, 'fetchTestData').mockResolvedValueOnce([
|
|
1744
|
+
{
|
|
1745
|
+
testPointsItems: [{ testCaseId: 122, testCaseName: 'TC 122' }],
|
|
1746
|
+
testCasesItems: [
|
|
1747
|
+
{
|
|
1748
|
+
workItem: {
|
|
1749
|
+
id: 122,
|
|
1750
|
+
workItemFields: [
|
|
1751
|
+
{ key: 'Steps', value: '<steps></steps>' },
|
|
1752
|
+
{
|
|
1753
|
+
key: 'System.Description',
|
|
1754
|
+
value: `
|
|
1755
|
+
<p>Intro</p>
|
|
1756
|
+
<b><u>TRIAL SPECIFIC ASSUMPTIONS, constraints</u></b>
|
|
1757
|
+
<p>- SR0501</p>
|
|
1758
|
+
`,
|
|
1759
|
+
},
|
|
1760
|
+
],
|
|
1761
|
+
},
|
|
1762
|
+
},
|
|
1763
|
+
],
|
|
1764
|
+
},
|
|
1765
|
+
]);
|
|
1766
|
+
jest.spyOn(resultDataProvider, 'fetchMewpL2Requirements').mockResolvedValueOnce([
|
|
1767
|
+
{
|
|
1768
|
+
workItemId: 8501,
|
|
1769
|
+
requirementId: 'SR0501',
|
|
1770
|
+
baseKey: 'SR0501',
|
|
1771
|
+
title: 'Req 501',
|
|
1772
|
+
responsibility: 'ESUK',
|
|
1773
|
+
linkedTestCaseIds: [],
|
|
1774
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1775
|
+
},
|
|
1776
|
+
]);
|
|
1777
|
+
jest.spyOn(resultDataProvider, 'buildLinkedRequirementsByTestCase').mockResolvedValueOnce(new Map([
|
|
1778
|
+
[
|
|
1779
|
+
122,
|
|
1780
|
+
{
|
|
1781
|
+
baseKeys: new Set(['SR0501']),
|
|
1782
|
+
fullCodes: new Set(['SR0501']),
|
|
1783
|
+
},
|
|
1784
|
+
],
|
|
1785
|
+
]));
|
|
1786
|
+
jest.spyOn(resultDataProvider.testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
|
|
1787
|
+
{
|
|
1788
|
+
stepId: '1',
|
|
1789
|
+
stepPosition: '1',
|
|
1790
|
+
action: '',
|
|
1791
|
+
expected: '',
|
|
1792
|
+
isSharedStepTitle: false,
|
|
1793
|
+
},
|
|
1794
|
+
]);
|
|
1795
|
+
const result = await resultDataProvider.getMewpInternalValidationFlatResults('123', mockProjectName, [1]);
|
|
1796
|
+
expect(result.rows).toHaveLength(1);
|
|
1797
|
+
expect(result.rows[0]).toEqual(expect.objectContaining({
|
|
1798
|
+
'Mentioned but Not Linked': '',
|
|
1799
|
+
'Linked but Not Mentioned': '',
|
|
1800
|
+
'Validation Status': 'Pass',
|
|
1801
|
+
}));
|
|
1802
|
+
});
|
|
1803
|
+
it('should treat compact <u><b>...</b></u> titles as section boundaries in description parsing', async () => {
|
|
1804
|
+
jest.spyOn(resultDataProvider, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1805
|
+
jest.spyOn(resultDataProvider, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
1806
|
+
jest.spyOn(resultDataProvider, 'fetchTestData').mockResolvedValueOnce([
|
|
1807
|
+
{
|
|
1808
|
+
testPointsItems: [{ testCaseId: 123, testCaseName: 'TC 123' }],
|
|
1809
|
+
testCasesItems: [
|
|
1810
|
+
{
|
|
1811
|
+
workItem: {
|
|
1812
|
+
id: 123,
|
|
1813
|
+
workItemFields: [
|
|
1814
|
+
{ key: 'Steps', value: '<steps></steps>' },
|
|
1815
|
+
{
|
|
1816
|
+
key: 'System.Description',
|
|
1817
|
+
value: '<b><u>Trial specific assumptions, constraints, dependencies and requirements</u></b><p>SR0100</p><u><b>another title</b></u><p>SR2242</p>',
|
|
1818
|
+
},
|
|
1819
|
+
],
|
|
1820
|
+
},
|
|
1821
|
+
},
|
|
1822
|
+
],
|
|
1823
|
+
},
|
|
1824
|
+
]);
|
|
1825
|
+
jest.spyOn(resultDataProvider, 'fetchMewpL2Requirements').mockResolvedValueOnce([
|
|
1826
|
+
{
|
|
1827
|
+
workItemId: 8100,
|
|
1828
|
+
requirementId: 'SR0100',
|
|
1829
|
+
baseKey: 'SR0100',
|
|
1830
|
+
title: 'Req 100',
|
|
1831
|
+
responsibility: 'ESUK',
|
|
1832
|
+
linkedTestCaseIds: [],
|
|
1833
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
workItemId: 82242,
|
|
1837
|
+
requirementId: 'SR2242',
|
|
1838
|
+
baseKey: 'SR2242',
|
|
1839
|
+
title: 'Req 2242',
|
|
1840
|
+
responsibility: 'ESUK',
|
|
1841
|
+
linkedTestCaseIds: [],
|
|
1842
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1843
|
+
},
|
|
1844
|
+
]);
|
|
1845
|
+
jest
|
|
1846
|
+
.spyOn(resultDataProvider, 'buildLinkedRequirementsByTestCase')
|
|
1847
|
+
.mockResolvedValueOnce(new Map([[123, { baseKeys: new Set(), fullCodes: new Set() }]]));
|
|
1848
|
+
jest.spyOn(resultDataProvider.testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
|
|
1849
|
+
{
|
|
1850
|
+
stepId: '1',
|
|
1851
|
+
stepPosition: '1',
|
|
1852
|
+
action: '',
|
|
1853
|
+
expected: '',
|
|
1854
|
+
isSharedStepTitle: false,
|
|
1855
|
+
},
|
|
1856
|
+
]);
|
|
1857
|
+
const result = await resultDataProvider.getMewpInternalValidationFlatResults('123', mockProjectName, [1]);
|
|
1858
|
+
expect(result.rows).toHaveLength(1);
|
|
1859
|
+
const directionA = String(result.rows[0]['Mentioned but Not Linked'] || '');
|
|
1860
|
+
expect(directionA).toContain('Assumptions: SR0100');
|
|
1861
|
+
expect(directionA).not.toContain('SR2242');
|
|
1862
|
+
});
|
|
1863
|
+
it('should treat nested <u> titles as section boundaries in description parsing', async () => {
|
|
1864
|
+
jest.spyOn(resultDataProvider, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1865
|
+
jest.spyOn(resultDataProvider, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
1866
|
+
jest.spyOn(resultDataProvider, 'fetchTestData').mockResolvedValueOnce([
|
|
1867
|
+
{
|
|
1868
|
+
testPointsItems: [{ testCaseId: 124, testCaseName: 'TC 124' }],
|
|
1869
|
+
testCasesItems: [
|
|
1870
|
+
{
|
|
1871
|
+
workItem: {
|
|
1872
|
+
id: 124,
|
|
1873
|
+
workItemFields: [
|
|
1874
|
+
{ key: 'Steps', value: '<steps></steps>' },
|
|
1875
|
+
{
|
|
1876
|
+
key: 'System.Description',
|
|
1877
|
+
value: '<u>Trial specific assumptions, constraints, dependencies and requirements</u><p>SR0100</p><u><u>Nested title</u></u><p>SR2242</p>',
|
|
1878
|
+
},
|
|
1879
|
+
],
|
|
1880
|
+
},
|
|
1881
|
+
},
|
|
1882
|
+
],
|
|
1883
|
+
},
|
|
1884
|
+
]);
|
|
1885
|
+
jest.spyOn(resultDataProvider, 'fetchMewpL2Requirements').mockResolvedValueOnce([
|
|
1886
|
+
{
|
|
1887
|
+
workItemId: 9100,
|
|
1888
|
+
requirementId: 'SR0100',
|
|
1889
|
+
baseKey: 'SR0100',
|
|
1890
|
+
title: 'Req 100',
|
|
1891
|
+
responsibility: 'ESUK',
|
|
1892
|
+
linkedTestCaseIds: [],
|
|
1893
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1894
|
+
},
|
|
1895
|
+
{
|
|
1896
|
+
workItemId: 92242,
|
|
1897
|
+
requirementId: 'SR2242',
|
|
1898
|
+
baseKey: 'SR2242',
|
|
1899
|
+
title: 'Req 2242',
|
|
1900
|
+
responsibility: 'ESUK',
|
|
1901
|
+
linkedTestCaseIds: [],
|
|
1902
|
+
areaPath: 'MEWP\\Customer Requirements\\Level 2',
|
|
1903
|
+
},
|
|
1904
|
+
]);
|
|
1905
|
+
jest
|
|
1906
|
+
.spyOn(resultDataProvider, 'buildLinkedRequirementsByTestCase')
|
|
1907
|
+
.mockResolvedValueOnce(new Map([[124, { baseKeys: new Set(), fullCodes: new Set() }]]));
|
|
1908
|
+
jest.spyOn(resultDataProvider.testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
|
|
1909
|
+
{
|
|
1910
|
+
stepId: '1',
|
|
1911
|
+
stepPosition: '1',
|
|
1912
|
+
action: '',
|
|
1913
|
+
expected: '',
|
|
1914
|
+
isSharedStepTitle: false,
|
|
1915
|
+
},
|
|
1916
|
+
]);
|
|
1917
|
+
const result = await resultDataProvider.getMewpInternalValidationFlatResults('123', mockProjectName, [1]);
|
|
1918
|
+
expect(result.rows).toHaveLength(1);
|
|
1919
|
+
const directionA = String(result.rows[0]['Mentioned but Not Linked'] || '');
|
|
1920
|
+
expect(directionA).toContain('Assumptions: SR0100');
|
|
1921
|
+
expect(directionA).not.toContain('SR2242');
|
|
1922
|
+
});
|
|
1589
1923
|
it('should emit Direction A rows only for specifically mentioned child requirements', async () => {
|
|
1590
1924
|
jest.spyOn(resultDataProvider, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1591
1925
|
jest.spyOn(resultDataProvider, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|