@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.
@@ -1126,6 +1126,62 @@ describe('ResultDataProvider', () => {
1126
1126
  });
1127
1127
 
1128
1128
  describe('getMewpL2CoverageFlatResults', () => {
1129
+ it('should split SR prefix into SR # + L2 REQ Title while preserving full title', () => {
1130
+ const row = (resultDataProvider as any).createMewpCoverageRow(
1131
+ {
1132
+ workItemId: 5054,
1133
+ requirementId: 'SR0054',
1134
+ title: 'SR0054 - Engine startup coverage',
1135
+ owner: 'ESUK',
1136
+ subSystem: 'Propulsion',
1137
+ responsibility: 'ESUK',
1138
+ },
1139
+ 'Pass',
1140
+ { id: '', title: '', responsibility: '' },
1141
+ { l3Id: '', l3Title: '', l4Id: '', l4Title: '' }
1142
+ );
1143
+
1144
+ expect(row).toEqual(
1145
+ expect.objectContaining({
1146
+ 'L2 REQ ID': '5054',
1147
+ 'SR #': 'SR0054',
1148
+ 'L2 REQ Title': 'Engine startup coverage',
1149
+ 'L2 REQ Full Title': 'SR0054 - Engine startup coverage',
1150
+ 'L2 Owner': 'ESUK',
1151
+ 'L2 SubSystem': 'Propulsion',
1152
+ })
1153
+ );
1154
+ });
1155
+
1156
+ it('should keep full title when title is only the SR token', () => {
1157
+ const row = (resultDataProvider as any).createMewpCoverageRow(
1158
+ {
1159
+ workItemId: 9999,
1160
+ requirementId: 'SR9999',
1161
+ title: 'SR9999',
1162
+ owner: 'IL',
1163
+ subSystem: '',
1164
+ responsibility: 'IL',
1165
+ },
1166
+ 'Not Run',
1167
+ { id: '', title: '', responsibility: '' },
1168
+ { l3Id: '', l3Title: '', l4Id: '', l4Title: '' }
1169
+ );
1170
+
1171
+ expect(row['L2 REQ Title']).toBe('SR9999');
1172
+ expect(row['L2 REQ Full Title']).toBe('SR9999');
1173
+ expect(row['L2 Owner']).toBe('IL');
1174
+ });
1175
+
1176
+ it('should resolve L2 run status precedence: Fail > Not Run > Pass', () => {
1177
+ const resolve = (resultDataProvider as any).resolveMewpL2RunStatus.bind(resultDataProvider as any);
1178
+
1179
+ expect(resolve({ passed: 2, failed: 1, notRun: 3, hasAnyTestCase: true })).toBe('Fail');
1180
+ expect(resolve({ passed: 5, failed: 0, notRun: 1, hasAnyTestCase: true })).toBe('Not Run');
1181
+ expect(resolve({ passed: 1, failed: 0, notRun: 0, hasAnyTestCase: true })).toBe('Pass');
1182
+ expect(resolve({ passed: 0, failed: 0, notRun: 0, hasAnyTestCase: true })).toBe('Not Run');
1183
+ });
1184
+
1129
1185
  it('should fetch MEWP scoped test data from selected suites', async () => {
1130
1186
  jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
1131
1187
  const scopedSpy = jest
@@ -1234,7 +1290,7 @@ describe('ResultDataProvider', () => {
1234
1290
  expect(result).toEqual(
1235
1291
  expect.objectContaining({
1236
1292
  sheetName: expect.stringContaining('MEWP L2 Coverage'),
1237
- columnOrder: expect.arrayContaining(['L2 REQ ID', 'L2 REQ Title', 'L2 Run Status']),
1293
+ columnOrder: expect.arrayContaining(['L2 REQ ID', 'SR #', 'L2 REQ Title', 'L2 Owner', 'L2 Run Status']),
1238
1294
  })
1239
1295
  );
1240
1296
 
@@ -1980,6 +2036,338 @@ describe('ResultDataProvider', () => {
1980
2036
  );
1981
2037
  });
1982
2038
 
2039
+ it('should parse requirement mentions only from the assumptions section in test-case description', async () => {
2040
+ jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
2041
+ jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
2042
+ jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
2043
+ {
2044
+ testPointsItems: [{ testCaseId: 121, testCaseName: 'TC 121' }],
2045
+ testCasesItems: [
2046
+ {
2047
+ workItem: {
2048
+ id: 121,
2049
+ workItemFields: [
2050
+ { key: 'Steps', value: '<steps></steps>' },
2051
+ {
2052
+ key: 'System.Description',
2053
+ value: `
2054
+ <p>Some intro text</p>
2055
+ <b><u>Trial specific assumptions, constraints, dependencies and requirements</u></b>
2056
+ <p>- VVRM-1 &amp; SR0100 - some text 1</p>
2057
+ <p>- VVRM-3 &amp; SR0588 - some text 2</p>
2058
+ <p>- SR1234, SR5678, SR1212</p>
2059
+ <p>some other text</p>
2060
+ <u><b>another title</b></u>
2061
+ <p>SR2242</p>
2062
+ `,
2063
+ },
2064
+ ],
2065
+ },
2066
+ },
2067
+ ],
2068
+ },
2069
+ ]);
2070
+ jest.spyOn(resultDataProvider as any, 'fetchMewpL2Requirements').mockResolvedValueOnce([
2071
+ {
2072
+ workItemId: 8100,
2073
+ requirementId: 'SR0100',
2074
+ baseKey: 'SR0100',
2075
+ title: 'Req 100',
2076
+ responsibility: 'ESUK',
2077
+ linkedTestCaseIds: [],
2078
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2079
+ },
2080
+ {
2081
+ workItemId: 8588,
2082
+ requirementId: 'SR0588',
2083
+ baseKey: 'SR0588',
2084
+ title: 'Req 588',
2085
+ responsibility: 'ESUK',
2086
+ linkedTestCaseIds: [],
2087
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2088
+ },
2089
+ {
2090
+ workItemId: 91234,
2091
+ requirementId: 'SR1234',
2092
+ baseKey: 'SR1234',
2093
+ title: 'Req 1234',
2094
+ responsibility: 'ESUK',
2095
+ linkedTestCaseIds: [],
2096
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2097
+ },
2098
+ {
2099
+ workItemId: 95678,
2100
+ requirementId: 'SR5678',
2101
+ baseKey: 'SR5678',
2102
+ title: 'Req 5678',
2103
+ responsibility: 'ESUK',
2104
+ linkedTestCaseIds: [],
2105
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2106
+ },
2107
+ {
2108
+ workItemId: 91212,
2109
+ requirementId: 'SR1212',
2110
+ baseKey: 'SR1212',
2111
+ title: 'Req 1212',
2112
+ responsibility: 'ESUK',
2113
+ linkedTestCaseIds: [],
2114
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2115
+ },
2116
+ {
2117
+ workItemId: 92242,
2118
+ requirementId: 'SR2242',
2119
+ baseKey: 'SR2242',
2120
+ title: 'Req 2242',
2121
+ responsibility: 'ESUK',
2122
+ linkedTestCaseIds: [],
2123
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2124
+ },
2125
+ ]);
2126
+ jest
2127
+ .spyOn(resultDataProvider as any, 'buildLinkedRequirementsByTestCase')
2128
+ .mockResolvedValueOnce(new Map([[121, { baseKeys: new Set<string>(), fullCodes: new Set<string>() }]]));
2129
+ jest.spyOn((resultDataProvider as any).testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
2130
+ {
2131
+ stepId: '1',
2132
+ stepPosition: '1',
2133
+ action: '',
2134
+ expected: '',
2135
+ isSharedStepTitle: false,
2136
+ },
2137
+ ]);
2138
+
2139
+ const result = await (resultDataProvider as any).getMewpInternalValidationFlatResults(
2140
+ '123',
2141
+ mockProjectName,
2142
+ [1]
2143
+ );
2144
+
2145
+ expect(result.rows).toHaveLength(1);
2146
+ const directionA = String(result.rows[0]['Mentioned but Not Linked'] || '');
2147
+ expect(directionA).toContain('Assumptions:');
2148
+ expect(directionA).toContain('SR0100');
2149
+ expect(directionA).toContain('SR0588');
2150
+ expect(directionA).toContain('SR1234');
2151
+ expect(directionA).toContain('SR5678');
2152
+ expect(directionA).toContain('SR1212');
2153
+ expect(directionA).not.toContain('SR2242');
2154
+ expect(result.rows[0]).toEqual(
2155
+ expect.objectContaining({
2156
+ 'Validation Status': 'Fail',
2157
+ })
2158
+ );
2159
+ });
2160
+
2161
+ it('should detect assumptions heading case-insensitively in description', async () => {
2162
+ jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
2163
+ jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
2164
+ jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
2165
+ {
2166
+ testPointsItems: [{ testCaseId: 122, testCaseName: 'TC 122' }],
2167
+ testCasesItems: [
2168
+ {
2169
+ workItem: {
2170
+ id: 122,
2171
+ workItemFields: [
2172
+ { key: 'Steps', value: '<steps></steps>' },
2173
+ {
2174
+ key: 'System.Description',
2175
+ value: `
2176
+ <p>Intro</p>
2177
+ <b><u>TRIAL SPECIFIC ASSUMPTIONS, constraints</u></b>
2178
+ <p>- SR0501</p>
2179
+ `,
2180
+ },
2181
+ ],
2182
+ },
2183
+ },
2184
+ ],
2185
+ },
2186
+ ]);
2187
+ jest.spyOn(resultDataProvider as any, 'fetchMewpL2Requirements').mockResolvedValueOnce([
2188
+ {
2189
+ workItemId: 8501,
2190
+ requirementId: 'SR0501',
2191
+ baseKey: 'SR0501',
2192
+ title: 'Req 501',
2193
+ responsibility: 'ESUK',
2194
+ linkedTestCaseIds: [],
2195
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2196
+ },
2197
+ ]);
2198
+ jest.spyOn(resultDataProvider as any, 'buildLinkedRequirementsByTestCase').mockResolvedValueOnce(
2199
+ new Map([
2200
+ [
2201
+ 122,
2202
+ {
2203
+ baseKeys: new Set(['SR0501']),
2204
+ fullCodes: new Set(['SR0501']),
2205
+ },
2206
+ ],
2207
+ ])
2208
+ );
2209
+ jest.spyOn((resultDataProvider as any).testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
2210
+ {
2211
+ stepId: '1',
2212
+ stepPosition: '1',
2213
+ action: '',
2214
+ expected: '',
2215
+ isSharedStepTitle: false,
2216
+ },
2217
+ ]);
2218
+
2219
+ const result = await (resultDataProvider as any).getMewpInternalValidationFlatResults(
2220
+ '123',
2221
+ mockProjectName,
2222
+ [1]
2223
+ );
2224
+
2225
+ expect(result.rows).toHaveLength(1);
2226
+ expect(result.rows[0]).toEqual(
2227
+ expect.objectContaining({
2228
+ 'Mentioned but Not Linked': '',
2229
+ 'Linked but Not Mentioned': '',
2230
+ 'Validation Status': 'Pass',
2231
+ })
2232
+ );
2233
+ });
2234
+
2235
+ it('should treat compact <u><b>...</b></u> titles as section boundaries in description parsing', async () => {
2236
+ jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
2237
+ jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
2238
+ jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
2239
+ {
2240
+ testPointsItems: [{ testCaseId: 123, testCaseName: 'TC 123' }],
2241
+ testCasesItems: [
2242
+ {
2243
+ workItem: {
2244
+ id: 123,
2245
+ workItemFields: [
2246
+ { key: 'Steps', value: '<steps></steps>' },
2247
+ {
2248
+ key: 'System.Description',
2249
+ value:
2250
+ '<b><u>Trial specific assumptions, constraints, dependencies and requirements</u></b><p>SR0100</p><u><b>another title</b></u><p>SR2242</p>',
2251
+ },
2252
+ ],
2253
+ },
2254
+ },
2255
+ ],
2256
+ },
2257
+ ]);
2258
+ jest.spyOn(resultDataProvider as any, 'fetchMewpL2Requirements').mockResolvedValueOnce([
2259
+ {
2260
+ workItemId: 8100,
2261
+ requirementId: 'SR0100',
2262
+ baseKey: 'SR0100',
2263
+ title: 'Req 100',
2264
+ responsibility: 'ESUK',
2265
+ linkedTestCaseIds: [],
2266
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2267
+ },
2268
+ {
2269
+ workItemId: 82242,
2270
+ requirementId: 'SR2242',
2271
+ baseKey: 'SR2242',
2272
+ title: 'Req 2242',
2273
+ responsibility: 'ESUK',
2274
+ linkedTestCaseIds: [],
2275
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2276
+ },
2277
+ ]);
2278
+ jest
2279
+ .spyOn(resultDataProvider as any, 'buildLinkedRequirementsByTestCase')
2280
+ .mockResolvedValueOnce(new Map([[123, { baseKeys: new Set<string>(), fullCodes: new Set<string>() }]]));
2281
+ jest.spyOn((resultDataProvider as any).testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
2282
+ {
2283
+ stepId: '1',
2284
+ stepPosition: '1',
2285
+ action: '',
2286
+ expected: '',
2287
+ isSharedStepTitle: false,
2288
+ },
2289
+ ]);
2290
+
2291
+ const result = await (resultDataProvider as any).getMewpInternalValidationFlatResults(
2292
+ '123',
2293
+ mockProjectName,
2294
+ [1]
2295
+ );
2296
+
2297
+ expect(result.rows).toHaveLength(1);
2298
+ const directionA = String(result.rows[0]['Mentioned but Not Linked'] || '');
2299
+ expect(directionA).toContain('Assumptions: SR0100');
2300
+ expect(directionA).not.toContain('SR2242');
2301
+ });
2302
+
2303
+ it('should treat nested <u> titles as section boundaries in description parsing', async () => {
2304
+ jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
2305
+ jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
2306
+ jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
2307
+ {
2308
+ testPointsItems: [{ testCaseId: 124, testCaseName: 'TC 124' }],
2309
+ testCasesItems: [
2310
+ {
2311
+ workItem: {
2312
+ id: 124,
2313
+ workItemFields: [
2314
+ { key: 'Steps', value: '<steps></steps>' },
2315
+ {
2316
+ key: 'System.Description',
2317
+ value:
2318
+ '<u>Trial specific assumptions, constraints, dependencies and requirements</u><p>SR0100</p><u><u>Nested title</u></u><p>SR2242</p>',
2319
+ },
2320
+ ],
2321
+ },
2322
+ },
2323
+ ],
2324
+ },
2325
+ ]);
2326
+ jest.spyOn(resultDataProvider as any, 'fetchMewpL2Requirements').mockResolvedValueOnce([
2327
+ {
2328
+ workItemId: 9100,
2329
+ requirementId: 'SR0100',
2330
+ baseKey: 'SR0100',
2331
+ title: 'Req 100',
2332
+ responsibility: 'ESUK',
2333
+ linkedTestCaseIds: [],
2334
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2335
+ },
2336
+ {
2337
+ workItemId: 92242,
2338
+ requirementId: 'SR2242',
2339
+ baseKey: 'SR2242',
2340
+ title: 'Req 2242',
2341
+ responsibility: 'ESUK',
2342
+ linkedTestCaseIds: [],
2343
+ areaPath: 'MEWP\\Customer Requirements\\Level 2',
2344
+ },
2345
+ ]);
2346
+ jest
2347
+ .spyOn(resultDataProvider as any, 'buildLinkedRequirementsByTestCase')
2348
+ .mockResolvedValueOnce(new Map([[124, { baseKeys: new Set<string>(), fullCodes: new Set<string>() }]]));
2349
+ jest.spyOn((resultDataProvider as any).testStepParserHelper, 'parseTestSteps').mockResolvedValueOnce([
2350
+ {
2351
+ stepId: '1',
2352
+ stepPosition: '1',
2353
+ action: '',
2354
+ expected: '',
2355
+ isSharedStepTitle: false,
2356
+ },
2357
+ ]);
2358
+
2359
+ const result = await (resultDataProvider as any).getMewpInternalValidationFlatResults(
2360
+ '123',
2361
+ mockProjectName,
2362
+ [1]
2363
+ );
2364
+
2365
+ expect(result.rows).toHaveLength(1);
2366
+ const directionA = String(result.rows[0]['Mentioned but Not Linked'] || '');
2367
+ expect(directionA).toContain('Assumptions: SR0100');
2368
+ expect(directionA).not.toContain('SR2242');
2369
+ });
2370
+
1983
2371
  it('should emit Direction A rows only for specifically mentioned child requirements', async () => {
1984
2372
  jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
1985
2373
  jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);