@elisra-devops/docgen-data-provider 1.87.0 → 1.89.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.
@@ -296,7 +296,7 @@ class ResultDataProvider {
296
296
  };
297
297
  try {
298
298
  const planName = await this.fetchTestPlanName(testPlanId, projectName);
299
- const testData = await this.fetchMewpScopedTestData(testPlanId, projectName, selectedSuiteIds, !!(options === null || options === void 0 ? void 0 : options.useRelFallback));
299
+ const testData = await this.fetchMewpScopedTestData(testPlanId, projectName, selectedSuiteIds);
300
300
  const allRequirements = await this.fetchMewpL2Requirements(projectName);
301
301
  if (allRequirements.length === 0) {
302
302
  return Object.assign(Object.assign({}, defaultPayload), { sheetName: this.buildMewpCoverageSheetName(planName, testPlanId) });
@@ -348,6 +348,9 @@ class ResultDataProvider {
348
348
  const parsedDefinitionStepsByTestCase = new Map();
349
349
  const testCaseStepsXmlMap = this.buildTestCaseStepsXmlMap(testData);
350
350
  const runResults = await this.fetchAllResultDataTestReporter(testData, projectName, [], false, false);
351
+ if (options === null || options === void 0 ? void 0 : options.debugMode) {
352
+ this.logMewpRunScenarioDebugMatrix(runResults, `coverage plan=${testPlanId}`);
353
+ }
351
354
  for (const runResult of runResults) {
352
355
  const testCaseId = this.extractMewpTestCaseId(runResult);
353
356
  const rawActionResults = Array.isArray((_j = runResult === null || runResult === void 0 ? void 0 : runResult.iteration) === null || _j === void 0 ? void 0 : _j.actionResults)
@@ -484,7 +487,7 @@ class ResultDataProvider {
484
487
  };
485
488
  try {
486
489
  const planName = await this.fetchTestPlanName(testPlanId, projectName);
487
- const testData = await this.fetchMewpScopedTestData(testPlanId, projectName, selectedSuiteIds, !!(options === null || options === void 0 ? void 0 : options.useRelFallback));
490
+ const testData = await this.fetchMewpScopedTestData(testPlanId, projectName, selectedSuiteIds);
488
491
  const allRequirements = await this.fetchMewpL2Requirements(projectName);
489
492
  const linkedRequirementsByTestCase = await this.buildLinkedRequirementsByTestCase(allRequirements, testData, projectName);
490
493
  const scopedRequirementKeys = await this.resolveMewpRequirementScopeKeysFromQuery(linkedQueryRequest, allRequirements, linkedRequirementsByTestCase);
@@ -512,6 +515,10 @@ class ResultDataProvider {
512
515
  logger_1.default.info(`MEWP internal validation steps source summary: testCases=${allTestCaseIds.size} ` +
513
516
  `fromSuitePayload=${preloadedStepXmlCount} fromWorkItemFallback=${fallbackStepLoadStats.loadedFromFallback} ` +
514
517
  `stepsXmlAvailable=${stepsXmlByTestCase.size} unresolved=${fallbackStepLoadStats.unresolvedCount}`);
518
+ if (options === null || options === void 0 ? void 0 : options.debugMode) {
519
+ const debugRunResults = await this.fetchAllResultDataTestReporter(testData, projectName, [], false, false);
520
+ this.logMewpRunScenarioDebugMatrix(debugRunResults, `internal-validation plan=${testPlanId}`);
521
+ }
515
522
  const validL2BaseKeys = new Set([...requirementFamilies.keys()]);
516
523
  const diagnostics = {
517
524
  totalTestCases: 0,
@@ -617,8 +624,9 @@ class ResultDataProvider {
617
624
  for (const code of mentionedCodes) {
618
625
  const hasSpecificSuffix = /-\d+$/.test(code);
619
626
  if (hasSpecificSuffix) {
620
- if (!linkedFullCodes.has(code))
627
+ if (!linkedFullCodes.has(code)) {
621
628
  missingSpecificMentionedNoFamily.add(code);
629
+ }
622
630
  }
623
631
  else if (!linkedBaseKeys.has(baseKey)) {
624
632
  missingBaseWhenFamilyUncovered.add(baseKey);
@@ -681,7 +689,7 @@ class ResultDataProvider {
681
689
  const groupedRequirementList = this.formatRequirementCodesGroupedByFamily(requirementIds);
682
690
  return `${stepRef}: ${groupedRequirementList}`;
683
691
  })
684
- .join('; ');
692
+ .join('\n');
685
693
  const linkedButNotMentioned = this.formatRequirementCodesGroupedByFamily(sortedExtraLinked);
686
694
  const validationStatus = mentionedButNotLinked || linkedButNotMentioned ? 'Fail' : 'Pass';
687
695
  if (validationStatus === 'Fail')
@@ -1039,126 +1047,9 @@ class ResultDataProvider {
1039
1047
  return 'Pass';
1040
1048
  return (input === null || input === void 0 ? void 0 : input.hasAnyTestCase) ? 'Not Run' : 'Not Run';
1041
1049
  }
1042
- async fetchMewpScopedTestData(testPlanId, projectName, selectedSuiteIds, useRelFallback) {
1043
- if (!useRelFallback) {
1044
- const suites = await this.fetchTestSuites(testPlanId, projectName, selectedSuiteIds, true);
1045
- return this.fetchTestData(suites, projectName, testPlanId, false);
1046
- }
1047
- const selectedSuites = await this.fetchTestSuites(testPlanId, projectName, selectedSuiteIds, true);
1048
- const selectedRel = this.resolveMaxRelNumberFromSuites(selectedSuites);
1049
- if (selectedRel <= 0) {
1050
- return this.fetchTestData(selectedSuites, projectName, testPlanId, false);
1051
- }
1052
- const allSuites = await this.fetchTestSuites(testPlanId, projectName, undefined, true);
1053
- const relScopedSuites = allSuites.filter((suite) => {
1054
- const rel = this.extractRelNumberFromSuite(suite);
1055
- return rel > 0 && rel <= selectedRel;
1056
- });
1057
- const suitesForFetch = relScopedSuites.length > 0 ? relScopedSuites : selectedSuites;
1058
- const rawTestData = await this.fetchTestData(suitesForFetch, projectName, testPlanId, false);
1059
- return this.reduceToLatestRelRunPerTestCase(rawTestData);
1060
- }
1061
- extractRelNumberFromSuite(suite) {
1062
- const candidates = [
1063
- suite === null || suite === void 0 ? void 0 : suite.suiteName,
1064
- suite === null || suite === void 0 ? void 0 : suite.parentSuiteName,
1065
- suite === null || suite === void 0 ? void 0 : suite.suitePath,
1066
- suite === null || suite === void 0 ? void 0 : suite.testGroupName,
1067
- ];
1068
- const pattern = /(?:^|[^a-z0-9])rel\s*([0-9]+)/i;
1069
- for (const item of candidates) {
1070
- const match = pattern.exec(String(item || ''));
1071
- if (!match)
1072
- continue;
1073
- const parsed = Number(match[1]);
1074
- if (Number.isFinite(parsed) && parsed > 0) {
1075
- return parsed;
1076
- }
1077
- }
1078
- return 0;
1079
- }
1080
- resolveMaxRelNumberFromSuites(suites) {
1081
- let maxRel = 0;
1082
- for (const suite of suites || []) {
1083
- const rel = this.extractRelNumberFromSuite(suite);
1084
- if (rel > maxRel)
1085
- maxRel = rel;
1086
- }
1087
- return maxRel;
1088
- }
1089
- reduceToLatestRelRunPerTestCase(testData) {
1090
- var _a, _b;
1091
- const candidatesByTestCase = new Map();
1092
- const testCaseDefinitionById = new Map();
1093
- for (const suite of testData || []) {
1094
- const rel = this.extractRelNumberFromSuite(suite);
1095
- const testPointsItems = Array.isArray(suite === null || suite === void 0 ? void 0 : suite.testPointsItems) ? suite.testPointsItems : [];
1096
- const testCasesItems = Array.isArray(suite === null || suite === void 0 ? void 0 : suite.testCasesItems) ? suite.testCasesItems : [];
1097
- for (const testCase of testCasesItems) {
1098
- const testCaseId = Number(((_a = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _a === void 0 ? void 0 : _a.id) || (testCase === null || testCase === void 0 ? void 0 : testCase.testCaseId) || (testCase === null || testCase === void 0 ? void 0 : testCase.id) || 0);
1099
- if (!Number.isFinite(testCaseId) || testCaseId <= 0)
1100
- continue;
1101
- if (!testCaseDefinitionById.has(testCaseId)) {
1102
- testCaseDefinitionById.set(testCaseId, testCase);
1103
- }
1104
- }
1105
- for (const point of testPointsItems) {
1106
- const testCaseId = Number((point === null || point === void 0 ? void 0 : point.testCaseId) || ((_b = point === null || point === void 0 ? void 0 : point.testCase) === null || _b === void 0 ? void 0 : _b.id) || 0);
1107
- if (!Number.isFinite(testCaseId) || testCaseId <= 0)
1108
- continue;
1109
- const runId = Number((point === null || point === void 0 ? void 0 : point.lastRunId) || 0);
1110
- const resultId = Number((point === null || point === void 0 ? void 0 : point.lastResultId) || 0);
1111
- const hasRun = runId > 0 && resultId > 0;
1112
- if (!candidatesByTestCase.has(testCaseId)) {
1113
- candidatesByTestCase.set(testCaseId, []);
1114
- }
1115
- candidatesByTestCase.get(testCaseId).push({
1116
- point,
1117
- rel,
1118
- runId,
1119
- resultId,
1120
- hasRun,
1121
- });
1122
- }
1123
- }
1124
- const selectedPoints = [];
1125
- const selectedTestCaseIds = new Set();
1126
- for (const [testCaseId, candidates] of candidatesByTestCase.entries()) {
1127
- const sorted = [...candidates].sort((a, b) => {
1128
- if (a.hasRun !== b.hasRun)
1129
- return a.hasRun ? -1 : 1;
1130
- if (a.rel !== b.rel)
1131
- return b.rel - a.rel;
1132
- if (a.runId !== b.runId)
1133
- return b.runId - a.runId;
1134
- return b.resultId - a.resultId;
1135
- });
1136
- const chosen = sorted[0];
1137
- if (!(chosen === null || chosen === void 0 ? void 0 : chosen.point))
1138
- continue;
1139
- selectedPoints.push(chosen.point);
1140
- selectedTestCaseIds.add(testCaseId);
1141
- }
1142
- const selectedTestCases = [];
1143
- for (const testCaseId of selectedTestCaseIds) {
1144
- const definition = testCaseDefinitionById.get(testCaseId);
1145
- if (definition) {
1146
- selectedTestCases.push(definition);
1147
- }
1148
- }
1149
- return [
1150
- {
1151
- testSuiteId: 'MEWP_REL_SCOPED',
1152
- suiteId: 'MEWP_REL_SCOPED',
1153
- suiteName: 'MEWP Rel Scoped',
1154
- parentSuiteId: '',
1155
- parentSuiteName: '',
1156
- suitePath: 'MEWP Rel Scoped',
1157
- testGroupName: 'MEWP Rel Scoped',
1158
- testPointsItems: selectedPoints,
1159
- testCasesItems: selectedTestCases,
1160
- },
1161
- ];
1050
+ async fetchMewpScopedTestData(testPlanId, projectName, selectedSuiteIds) {
1051
+ const suites = await this.fetchTestSuites(testPlanId, projectName, selectedSuiteIds, true);
1052
+ return this.fetchTestData(suites, projectName, testPlanId, false);
1162
1053
  }
1163
1054
  async loadExternalBugsByTestCase(externalBugsFile) {
1164
1055
  return this.mewpExternalIngestionUtils.loadExternalBugsByTestCase(externalBugsFile, {
@@ -1473,16 +1364,6 @@ class ResultDataProvider {
1473
1364
  }
1474
1365
  return out;
1475
1366
  }
1476
- extractRequirementCodesFromExpectedSteps(steps, includeSuffix) {
1477
- const out = new Set();
1478
- for (const step of Array.isArray(steps) ? steps : []) {
1479
- if (step === null || step === void 0 ? void 0 : step.isSharedStepTitle)
1480
- continue;
1481
- const codes = this.extractRequirementCodesFromExpectedText((step === null || step === void 0 ? void 0 : step.expected) || '', includeSuffix);
1482
- codes.forEach((code) => out.add(code));
1483
- }
1484
- return out;
1485
- }
1486
1367
  extractRequirementCodesFromExpectedText(text, includeSuffix) {
1487
1368
  const out = new Set();
1488
1369
  const source = this.normalizeRequirementStepText(text);
@@ -2292,7 +2173,7 @@ class ResultDataProvider {
2292
2173
  return sortedMembers[0];
2293
2174
  return `${baseKey}: ${sortedMembers.join(', ')}`;
2294
2175
  })
2295
- .join('; ');
2176
+ .join('\n');
2296
2177
  }
2297
2178
  toMewpComparableText(value) {
2298
2179
  if (value === null || value === undefined)
@@ -2575,6 +2456,120 @@ class ResultDataProvider {
2575
2456
  const { value: testCases } = await tfs_1.TFSServices.getItemContent(url, this.token);
2576
2457
  return testCases;
2577
2458
  }
2459
+ attachSuiteTestCaseContextToPoints(testCasesItems, testPointsItems) {
2460
+ var _a;
2461
+ const points = Array.isArray(testPointsItems) ? testPointsItems : [];
2462
+ const testCases = Array.isArray(testCasesItems) ? testCasesItems : [];
2463
+ if (points.length === 0 || testCases.length === 0)
2464
+ return points;
2465
+ const byTestCaseId = new Map();
2466
+ for (const testCaseItem of testCases) {
2467
+ const testCaseId = Number(((_a = testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItem) === null || _a === void 0 ? void 0 : _a.id) || (testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.testCaseId) || (testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.id) || 0);
2468
+ if (!Number.isFinite(testCaseId) || testCaseId <= 0 || byTestCaseId.has(testCaseId))
2469
+ continue;
2470
+ byTestCaseId.set(testCaseId, testCaseItem);
2471
+ }
2472
+ return points.map((point) => {
2473
+ var _a;
2474
+ const testCaseId = Number((point === null || point === void 0 ? void 0 : point.testCaseId) || ((_a = point === null || point === void 0 ? void 0 : point.testCase) === null || _a === void 0 ? void 0 : _a.id) || 0);
2475
+ if (!Number.isFinite(testCaseId) || testCaseId <= 0)
2476
+ return point;
2477
+ const suiteTestCase = byTestCaseId.get(testCaseId);
2478
+ if (!suiteTestCase)
2479
+ return point;
2480
+ return Object.assign(Object.assign({}, point), { suiteTestCase });
2481
+ });
2482
+ }
2483
+ extractWorkItemFieldsMap(workItemFields) {
2484
+ const fields = {};
2485
+ if (!Array.isArray(workItemFields))
2486
+ return fields;
2487
+ for (const field of workItemFields) {
2488
+ const keyCandidates = [field === null || field === void 0 ? void 0 : field.key, field === null || field === void 0 ? void 0 : field.name, field === null || field === void 0 ? void 0 : field.referenceName]
2489
+ .map((item) => String(item || '').trim())
2490
+ .filter((item) => !!item);
2491
+ for (const key of keyCandidates) {
2492
+ fields[key] = field === null || field === void 0 ? void 0 : field.value;
2493
+ }
2494
+ }
2495
+ return fields;
2496
+ }
2497
+ resolveSuiteTestCaseRevision(testCaseItem) {
2498
+ var _a, _b, _c, _d, _e;
2499
+ const revisionCandidates = [
2500
+ (_a = testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItem) === null || _a === void 0 ? void 0 : _a.rev,
2501
+ (_b = testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItem) === null || _b === void 0 ? void 0 : _b.revision,
2502
+ (_c = testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItem) === null || _c === void 0 ? void 0 : _c.version,
2503
+ (_d = testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItem) === null || _d === void 0 ? void 0 : _d.workItemRevision,
2504
+ (_e = testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItem) === null || _e === void 0 ? void 0 : _e.workItemVersion,
2505
+ testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.revision,
2506
+ testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItemRevision,
2507
+ testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItemVersion,
2508
+ ];
2509
+ for (const candidate of revisionCandidates) {
2510
+ const parsed = Number(candidate || 0);
2511
+ if (Number.isFinite(parsed) && parsed > 0)
2512
+ return parsed;
2513
+ }
2514
+ return 0;
2515
+ }
2516
+ buildWorkItemSnapshotFromSuiteTestCase(testCaseItem, fallbackTestCaseId, fallbackTestCaseName = '') {
2517
+ var _a;
2518
+ if (!testCaseItem)
2519
+ return null;
2520
+ const testCaseId = Number(((_a = testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItem) === null || _a === void 0 ? void 0 : _a.id) || (testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.testCaseId) || (testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.id) || fallbackTestCaseId || 0);
2521
+ if (!Number.isFinite(testCaseId) || testCaseId <= 0)
2522
+ return null;
2523
+ const workItem = (testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.workItem) || {};
2524
+ const stepsXml = this.extractStepsXmlFromTestCaseItem(testCaseItem);
2525
+ const fieldsFromList = this.extractWorkItemFieldsMap(workItem === null || workItem === void 0 ? void 0 : workItem.workItemFields);
2526
+ const fieldsFromMap = (workItem === null || workItem === void 0 ? void 0 : workItem.fields) || {};
2527
+ const fields = Object.assign(Object.assign({}, fieldsFromList), fieldsFromMap);
2528
+ if (!fields['System.Title']) {
2529
+ const title = String((testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.testCaseName) || (workItem === null || workItem === void 0 ? void 0 : workItem.name) || (testCaseItem === null || testCaseItem === void 0 ? void 0 : testCaseItem.name) || fallbackTestCaseName || '').trim();
2530
+ if (title) {
2531
+ fields['System.Title'] = title;
2532
+ }
2533
+ }
2534
+ if (stepsXml && !fields['Microsoft.VSTS.TCM.Steps']) {
2535
+ fields['Microsoft.VSTS.TCM.Steps'] = stepsXml;
2536
+ }
2537
+ return {
2538
+ id: testCaseId,
2539
+ rev: this.resolveSuiteTestCaseRevision(testCaseItem) || 1,
2540
+ fields,
2541
+ relations: Array.isArray(workItem === null || workItem === void 0 ? void 0 : workItem.relations) ? workItem.relations : [],
2542
+ };
2543
+ }
2544
+ async fetchWorkItemByRevision(projectName, workItemId, revision, expandAll = false) {
2545
+ const id = Number(workItemId || 0);
2546
+ const rev = Number(revision || 0);
2547
+ if (!Number.isFinite(id) || id <= 0 || !Number.isFinite(rev) || rev <= 0)
2548
+ return null;
2549
+ const expandParam = expandAll ? '?$expand=all' : '';
2550
+ const url = `${this.orgUrl}${projectName}/_apis/wit/workItems/${id}/revisions/${rev}${expandParam}`;
2551
+ try {
2552
+ return await tfs_1.TFSServices.getItemContent(url, this.token);
2553
+ }
2554
+ catch (error) {
2555
+ logger_1.default.warn(`Failed to fetch work item ${id} by revision ${rev}: ${(error === null || error === void 0 ? void 0 : error.message) || error}`);
2556
+ return null;
2557
+ }
2558
+ }
2559
+ async fetchWorkItemLatest(projectName, workItemId, expandAll = false) {
2560
+ const id = Number(workItemId || 0);
2561
+ if (!Number.isFinite(id) || id <= 0)
2562
+ return null;
2563
+ const expandParam = expandAll ? '?$expand=all' : '';
2564
+ const url = `${this.orgUrl}${projectName}/_apis/wit/workItems/${id}${expandParam}`;
2565
+ try {
2566
+ return await tfs_1.TFSServices.getItemContent(url, this.token);
2567
+ }
2568
+ catch (error) {
2569
+ logger_1.default.warn(`Failed to fetch latest work item ${id}: ${(error === null || error === void 0 ? void 0 : error.message) || error}`);
2570
+ return null;
2571
+ }
2572
+ }
2578
2573
  /**
2579
2574
  * Fetches result data based on the Work Item Test Reporter.
2580
2575
  *
@@ -2590,7 +2585,7 @@ class ResultDataProvider {
2590
2585
  * @returns A promise that resolves to the fetched result data.
2591
2586
  */
2592
2587
  async fetchResultDataBasedOnWiBase(projectName, runId, resultId, isTestReporter = false, selectedFields, isQueryMode, point, includeAllHistory = false) {
2593
- var _a, _b, _c, _d, _e, _f, _g;
2588
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
2594
2589
  try {
2595
2590
  let filteredFields = {};
2596
2591
  let relatedRequirements = [];
@@ -2601,16 +2596,29 @@ class ResultDataProvider {
2601
2596
  logger_1.default.warn(`Invalid run result ${runId} or result ${resultId}`);
2602
2597
  return null;
2603
2598
  }
2604
- const url = `${this.orgUrl}${projectName}/_apis/wit/workItems/${point.testCaseId}?$expand=all`;
2605
- const testCaseData = await tfs_1.TFSServices.getItemContent(url, this.token);
2599
+ const suiteTestCaseItem = point === null || point === void 0 ? void 0 : point.suiteTestCase;
2600
+ const testCaseId = Number((point === null || point === void 0 ? void 0 : point.testCaseId) || ((_a = suiteTestCaseItem === null || suiteTestCaseItem === void 0 ? void 0 : suiteTestCaseItem.workItem) === null || _a === void 0 ? void 0 : _a.id) || (suiteTestCaseItem === null || suiteTestCaseItem === void 0 ? void 0 : suiteTestCaseItem.testCaseId) || 0);
2601
+ const suiteTestCaseRevision = this.resolveSuiteTestCaseRevision(suiteTestCaseItem);
2602
+ const fallbackSnapshot = this.buildWorkItemSnapshotFromSuiteTestCase(suiteTestCaseItem, testCaseId, String((point === null || point === void 0 ? void 0 : point.testCaseName) || ''));
2603
+ let testCaseData = await this.fetchWorkItemByRevision(projectName, testCaseId, suiteTestCaseRevision, isTestReporter);
2604
+ if (!testCaseData) {
2605
+ testCaseData = fallbackSnapshot;
2606
+ }
2607
+ if (!testCaseData) {
2608
+ testCaseData = await this.fetchWorkItemLatest(projectName, testCaseId, isTestReporter);
2609
+ }
2610
+ if (!testCaseData) {
2611
+ logger_1.default.warn(`Could not resolve test case ${point.testCaseId} for runless point fallback.`);
2612
+ return null;
2613
+ }
2606
2614
  const newResultData = {
2607
2615
  id: 0,
2608
2616
  outcome: point.outcome,
2609
- revision: (testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.rev) || 1,
2610
- testCase: { id: point.testCaseId, name: point.testCaseName },
2611
- state: ((_a = testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.fields) === null || _a === void 0 ? void 0 : _a['System.State']) || 'Active',
2612
- priority: ((_b = testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.fields) === null || _b === void 0 ? void 0 : _b['Microsoft.VSTS.TCM.Priority']) || 0,
2613
- createdDate: ((_c = testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.fields) === null || _c === void 0 ? void 0 : _c['System.CreatedDate']) || '0001-01-01T00:00:00',
2617
+ revision: Number((testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.rev) || suiteTestCaseRevision || 1),
2618
+ testCase: { id: String(testCaseId), name: point.testCaseName },
2619
+ state: ((_b = testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.fields) === null || _b === void 0 ? void 0 : _b['System.State']) || 'Active',
2620
+ priority: ((_c = testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.fields) === null || _c === void 0 ? void 0 : _c['Microsoft.VSTS.TCM.Priority']) || 0,
2621
+ createdDate: ((_d = testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.fields) === null || _d === void 0 ? void 0 : _d['System.CreatedDate']) || '0001-01-01T00:00:00',
2614
2622
  testSuite: point.testSuite,
2615
2623
  failureType: 'None',
2616
2624
  };
@@ -2618,7 +2626,7 @@ class ResultDataProvider {
2618
2626
  this.appendQueryRelations(point.testCaseId, relatedRequirements, relatedBugs, relatedCRs);
2619
2627
  }
2620
2628
  else {
2621
- const filteredLinkedFields = (_d = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@linked'))) === null || _d === void 0 ? void 0 : _d.map((field) => field.split('@')[0]);
2629
+ const filteredLinkedFields = (_e = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@linked'))) === null || _e === void 0 ? void 0 : _e.map((field) => field.split('@')[0]);
2622
2630
  const selectedLinkedFieldSet = new Set(filteredLinkedFields);
2623
2631
  const { relations } = testCaseData;
2624
2632
  if (relations) {
@@ -2626,7 +2634,7 @@ class ResultDataProvider {
2626
2634
  }
2627
2635
  selectedLinkedFieldSet.clear();
2628
2636
  }
2629
- const filteredTestCaseFields = (_e = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@testCaseWorkItemField'))) === null || _e === void 0 ? void 0 : _e.map((field) => field.split('@')[0]);
2637
+ const filteredTestCaseFields = (_f = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@testCaseWorkItemField'))) === null || _f === void 0 ? void 0 : _f.map((field) => field.split('@')[0]);
2630
2638
  const selectedFieldSet = new Set(filteredTestCaseFields);
2631
2639
  // Filter fields based on selected field set
2632
2640
  if (selectedFieldSet.size !== 0) {
@@ -2640,7 +2648,7 @@ class ResultDataProvider {
2640
2648
  }
2641
2649
  }
2642
2650
  selectedFieldSet.clear();
2643
- return Object.assign(Object.assign({}, newResultData), { stepsResultXml: testCaseData.fields['Microsoft.VSTS.TCM.Steps'] || undefined, testCaseRevision: testCaseData.rev, filteredFields,
2651
+ return Object.assign(Object.assign({}, newResultData), { stepsResultXml: ((_g = testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.fields) === null || _g === void 0 ? void 0 : _g['Microsoft.VSTS.TCM.Steps']) || undefined, testCaseRevision: Number((testCaseData === null || testCaseData === void 0 ? void 0 : testCaseData.rev) || suiteTestCaseRevision || 1), filteredFields,
2644
2652
  relatedRequirements,
2645
2653
  relatedBugs,
2646
2654
  relatedCRs });
@@ -2660,7 +2668,7 @@ class ResultDataProvider {
2660
2668
  this.appendQueryRelations(resultData.testCase.id, relatedRequirements, relatedBugs, relatedCRs);
2661
2669
  }
2662
2670
  else {
2663
- const filteredLinkedFields = (_f = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@linked'))) === null || _f === void 0 ? void 0 : _f.map((field) => field.split('@')[0]);
2671
+ const filteredLinkedFields = (_h = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@linked'))) === null || _h === void 0 ? void 0 : _h.map((field) => field.split('@')[0]);
2664
2672
  const selectedLinkedFieldSet = new Set(filteredLinkedFields);
2665
2673
  const { relations } = wiByRevision;
2666
2674
  if (relations) {
@@ -2668,7 +2676,7 @@ class ResultDataProvider {
2668
2676
  }
2669
2677
  selectedLinkedFieldSet.clear();
2670
2678
  }
2671
- const filteredTestCaseFields = (_g = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@testCaseWorkItemField'))) === null || _g === void 0 ? void 0 : _g.map((field) => field.split('@')[0]);
2679
+ const filteredTestCaseFields = (_j = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@testCaseWorkItemField'))) === null || _j === void 0 ? void 0 : _j.map((field) => field.split('@')[0]);
2672
2680
  const selectedFieldSet = new Set(filteredTestCaseFields);
2673
2681
  // Filter fields based on selected field set
2674
2682
  if (selectedFieldSet.size !== 0) {
@@ -2761,11 +2769,6 @@ class ResultDataProvider {
2761
2769
  return (String((_b = (_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.DOCGEN_VERBOSE_HISTORY_DEBUG) !== null && _b !== void 0 ? _b : '').toLowerCase() === 'true' ||
2762
2770
  String((_d = (_c = process === null || process === void 0 ? void 0 : process.env) === null || _c === void 0 ? void 0 : _c.DOCGEN_VERBOSE_HISTORY_DEBUG) !== null && _d !== void 0 ? _d : '') === '1');
2763
2771
  }
2764
- isRunResultDebugEnabled() {
2765
- var _a, _b, _c, _d;
2766
- return (String((_b = (_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.DOCGEN_DEBUG_RUNRESULT) !== null && _b !== void 0 ? _b : '').toLowerCase() === 'true' ||
2767
- String((_d = (_c = process === null || process === void 0 ? void 0 : process.env) === null || _c === void 0 ? void 0 : _c.DOCGEN_DEBUG_RUNRESULT) !== null && _d !== void 0 ? _d : '') === '1');
2768
- }
2769
2772
  extractCommentText(comment) {
2770
2773
  var _a, _b, _c, _d;
2771
2774
  const rendered = comment === null || comment === void 0 ? void 0 : comment.renderedText;
@@ -3161,6 +3164,71 @@ class ResultDataProvider {
3161
3164
  async fetchResultDataBasedOnWi(projectName, runId, resultId) {
3162
3165
  return this.fetchResultDataBasedOnWiBase(projectName, runId, resultId);
3163
3166
  }
3167
+ logMewpRunScenarioDebugMatrix(runResults, contextLabel) {
3168
+ var _a, _b;
3169
+ const results = Array.isArray(runResults) ? runResults : [];
3170
+ const matrix = {
3171
+ total: results.length,
3172
+ passOrFailWithActionResults: 0,
3173
+ runWithNoActionResults: 0,
3174
+ notApplicable: 0,
3175
+ noRunHistoryActive: 0,
3176
+ other: 0,
3177
+ };
3178
+ const samples = {
3179
+ passOrFailWithActionResults: [],
3180
+ runWithNoActionResults: [],
3181
+ notApplicable: [],
3182
+ noRunHistoryActive: [],
3183
+ other: [],
3184
+ };
3185
+ const pushSample = (bucket, id) => {
3186
+ if (!Number.isFinite(id) || id <= 0)
3187
+ return;
3188
+ if (samples[bucket].length >= 5)
3189
+ return;
3190
+ samples[bucket].push(id);
3191
+ };
3192
+ for (const item of results) {
3193
+ const testCaseId = Number((item === null || item === void 0 ? void 0 : item.testCaseId) || ((_a = item === null || item === void 0 ? void 0 : item.testCase) === null || _a === void 0 ? void 0 : _a.id) || 0);
3194
+ const hasRun = Number((item === null || item === void 0 ? void 0 : item.lastRunId) || 0) > 0 && Number((item === null || item === void 0 ? void 0 : item.lastResultId) || 0) > 0;
3195
+ const rawOutcome = String((item === null || item === void 0 ? void 0 : item._debugTestOutcome) || '').trim().toLowerCase();
3196
+ const rawState = String((item === null || item === void 0 ? void 0 : item._debugTestCaseState) || '').trim().toLowerCase();
3197
+ const originalActionResultsCount = Number((_b = item === null || item === void 0 ? void 0 : item._debugOriginalActionResultsCount) !== null && _b !== void 0 ? _b : -1);
3198
+ if (rawOutcome === 'notapplicable' || rawOutcome === 'not applicable') {
3199
+ matrix.notApplicable += 1;
3200
+ pushSample('notApplicable', testCaseId);
3201
+ continue;
3202
+ }
3203
+ if (hasRun && (rawOutcome === 'passed' || rawOutcome === 'failed') && originalActionResultsCount > 0) {
3204
+ matrix.passOrFailWithActionResults += 1;
3205
+ pushSample('passOrFailWithActionResults', testCaseId);
3206
+ continue;
3207
+ }
3208
+ if (hasRun && originalActionResultsCount === 0) {
3209
+ matrix.runWithNoActionResults += 1;
3210
+ pushSample('runWithNoActionResults', testCaseId);
3211
+ continue;
3212
+ }
3213
+ if (!hasRun && rawState === 'active') {
3214
+ matrix.noRunHistoryActive += 1;
3215
+ pushSample('noRunHistoryActive', testCaseId);
3216
+ continue;
3217
+ }
3218
+ matrix.other += 1;
3219
+ pushSample('other', testCaseId);
3220
+ }
3221
+ logger_1.default.info(`MEWP run debug matrix (${contextLabel}): total=${matrix.total}; ` +
3222
+ `passOrFailWithActionResults=${matrix.passOrFailWithActionResults}; ` +
3223
+ `runWithNoActionResults=${matrix.runWithNoActionResults}; ` +
3224
+ `notApplicable=${matrix.notApplicable}; ` +
3225
+ `noRunHistoryActive=${matrix.noRunHistoryActive}; other=${matrix.other}; ` +
3226
+ `samplePassFail=${samples.passOrFailWithActionResults.join(',') || '-'}; ` +
3227
+ `sampleNoAction=${samples.runWithNoActionResults.join(',') || '-'}; ` +
3228
+ `sampleNA=${samples.notApplicable.join(',') || '-'}; ` +
3229
+ `sampleNoRunActive=${samples.noRunHistoryActive.join(',') || '-'}; ` +
3230
+ `sampleOther=${samples.other.join(',') || '-'}`);
3231
+ }
3164
3232
  /**
3165
3233
  * Converts a run status string into a human-readable format.
3166
3234
  *
@@ -3369,9 +3437,10 @@ class ResultDataProvider {
3369
3437
  try {
3370
3438
  const testCasesItems = await this.fetchTestCasesBySuiteId(projectName, testPlanId, suite.testSuiteId);
3371
3439
  const testCaseIds = testCasesItems.map((testCase) => testCase.workItem.id);
3372
- const testPointsItems = !fetchCrossPlans
3440
+ const rawTestPointsItems = !fetchCrossPlans
3373
3441
  ? await this.fetchTestPoints(projectName, testPlanId, suite.testSuiteId)
3374
3442
  : await this.fetchCrossTestPoints(projectName, testCaseIds);
3443
+ const testPointsItems = this.attachSuiteTestCaseContextToPoints(testCasesItems, rawTestPointsItems);
3375
3444
  return Object.assign(Object.assign({}, suite), { testPointsItems, testCasesItems });
3376
3445
  }
3377
3446
  catch (error) {
@@ -3463,6 +3532,10 @@ class ResultDataProvider {
3463
3532
  }
3464
3533
  resultData.iterationDetails.push(iteration);
3465
3534
  }
3535
+ const originalActionResultsCount = Array.isArray(iteration === null || iteration === void 0 ? void 0 : iteration.actionResults)
3536
+ ? iteration.actionResults.length
3537
+ : 0;
3538
+ resultData._debugOriginalActionResultsCount = originalActionResultsCount;
3466
3539
  if (resultData.stepsResultXml && iteration) {
3467
3540
  const actionResults = Array.isArray(iteration.actionResults) ? iteration.actionResults : [];
3468
3541
  const actionResultsWithSharedModels = actionResults.filter((result) => result.sharedStepModel);
@@ -4004,12 +4077,13 @@ class ResultDataProvider {
4004
4077
  */
4005
4078
  async fetchResultDataForTestReporter(projectName, testSuiteId, point, selectedFields, isQueryMode, includeAllHistory = false) {
4006
4079
  return this.fetchResultDataBase(projectName, testSuiteId, point, (project, runId, resultId, fields, isQueryMode, point, includeAllHistory) => this.fetchResultDataBasedOnWiTestReporter(project, runId, resultId, fields, isQueryMode, point, includeAllHistory), (resultData, testSuiteId, point, selectedFields) => {
4007
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
4080
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
4008
4081
  const { lastRunId, lastResultId, configurationName, lastResultDetails } = point;
4009
4082
  try {
4010
4083
  const iteration = ((_a = resultData.iterationDetails) === null || _a === void 0 ? void 0 : _a.length) > 0
4011
4084
  ? resultData.iterationDetails[((_b = resultData.iterationDetails) === null || _b === void 0 ? void 0 : _b.length) - 1]
4012
4085
  : undefined;
4086
+ const debugOutcome = this.getTestOutcome(resultData);
4013
4087
  if (!(resultData === null || resultData === void 0 ? void 0 : resultData.testCase) || !(resultData === null || resultData === void 0 ? void 0 : resultData.testSuite)) {
4014
4088
  logger_1.default.debug(`[RunResult] Missing testCase/testSuite for point testCaseId=${String((_c = point === null || point === void 0 ? void 0 : point.testCaseId) !== null && _c !== void 0 ? _c : 'unknown')} (lastRunId=${String(lastRunId !== null && lastRunId !== void 0 ? lastRunId : '')}, lastResultId=${String(lastResultId !== null && lastResultId !== void 0 ? lastResultId : '')}). hasTestCase=${Boolean(resultData === null || resultData === void 0 ? void 0 : resultData.testCase)} hasTestSuite=${Boolean(resultData === null || resultData === void 0 ? void 0 : resultData.testSuite)}`);
4015
4089
  }
@@ -4034,13 +4108,16 @@ class ResultDataProvider {
4034
4108
  relatedCRs: resultData.relatedCRs || undefined,
4035
4109
  lastRunResult: undefined,
4036
4110
  customFields: {}, // Create an object to store custom fields
4111
+ _debugTestOutcome: debugOutcome,
4112
+ _debugTestCaseState: String((resultData === null || resultData === void 0 ? void 0 : resultData.state) || ''),
4113
+ _debugOriginalActionResultsCount: Number((_l = resultData === null || resultData === void 0 ? void 0 : resultData._debugOriginalActionResultsCount) !== null && _l !== void 0 ? _l : -1),
4037
4114
  };
4038
4115
  // Process all custom fields from resultData.filteredFields
4039
4116
  if (resultData.filteredFields) {
4040
4117
  const customFields = this.standardCustomField(resultData.filteredFields);
4041
4118
  resultDataResponse.customFields = customFields;
4042
4119
  }
4043
- const filteredFields = (_l = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@runResultField'))) === null || _l === void 0 ? void 0 : _l.map((field) => field.split('@')[0]);
4120
+ const filteredFields = (_m = selectedFields === null || selectedFields === void 0 ? void 0 : selectedFields.filter((field) => field.includes('@runResultField'))) === null || _m === void 0 ? void 0 : _m.map((field) => field.split('@')[0]);
4044
4121
  if (filteredFields && filteredFields.length > 0) {
4045
4122
  for (const field of filteredFields) {
4046
4123
  switch (field) {
@@ -4048,16 +4125,15 @@ class ResultDataProvider {
4048
4125
  resultDataResponse.priority = resultData.priority;
4049
4126
  break;
4050
4127
  case 'testCaseResult':
4051
- const outcome = this.getTestOutcome(resultData);
4052
4128
  if (lastRunId === undefined || lastResultId === undefined) {
4053
4129
  resultDataResponse.testCaseResult = {
4054
- resultMessage: `${this.convertRunStatus(outcome)}`,
4130
+ resultMessage: `${this.convertRunStatus(debugOutcome)}`,
4055
4131
  url: '',
4056
4132
  };
4057
4133
  }
4058
4134
  else {
4059
4135
  resultDataResponse.testCaseResult = {
4060
- resultMessage: `${this.convertRunStatus(outcome)} in Run ${lastRunId}`,
4136
+ resultMessage: `${this.convertRunStatus(debugOutcome)} in Run ${lastRunId}`,
4061
4137
  url: `${this.orgUrl}${projectName}/_testManagement/runs?runId=${lastRunId}&_a=resultSummary&resultId=${lastResultId}`,
4062
4138
  };
4063
4139
  }
@@ -4069,16 +4145,16 @@ class ResultDataProvider {
4069
4145
  resultDataResponse.failureType = resultData.failureType;
4070
4146
  break;
4071
4147
  case 'runBy':
4072
- if (!((_m = lastResultDetails === null || lastResultDetails === void 0 ? void 0 : lastResultDetails.runBy) === null || _m === void 0 ? void 0 : _m.displayName)) {
4073
- logger_1.default.debug(`[RunResult] Missing runBy for testCaseId=${String((_q = (_p = (_o = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _o === void 0 ? void 0 : _o.id) !== null && _p !== void 0 ? _p : point === null || point === void 0 ? void 0 : point.testCaseId) !== null && _q !== void 0 ? _q : 'unknown')} (lastRunId=${String(lastRunId !== null && lastRunId !== void 0 ? lastRunId : '')}, lastResultId=${String(lastResultId !== null && lastResultId !== void 0 ? lastResultId : '')}). lastResultDetails=${this.stringifyForDebug(lastResultDetails, 2000)}`);
4148
+ if (!((_o = lastResultDetails === null || lastResultDetails === void 0 ? void 0 : lastResultDetails.runBy) === null || _o === void 0 ? void 0 : _o.displayName)) {
4149
+ logger_1.default.debug(`[RunResult] Missing runBy for testCaseId=${String((_r = (_q = (_p = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _p === void 0 ? void 0 : _p.id) !== null && _q !== void 0 ? _q : point === null || point === void 0 ? void 0 : point.testCaseId) !== null && _r !== void 0 ? _r : 'unknown')} (lastRunId=${String(lastRunId !== null && lastRunId !== void 0 ? lastRunId : '')}, lastResultId=${String(lastResultId !== null && lastResultId !== void 0 ? lastResultId : '')}). lastResultDetails=${this.stringifyForDebug(lastResultDetails, 2000)}`);
4074
4150
  }
4075
- resultDataResponse.runBy = (_s = (_r = lastResultDetails === null || lastResultDetails === void 0 ? void 0 : lastResultDetails.runBy) === null || _r === void 0 ? void 0 : _r.displayName) !== null && _s !== void 0 ? _s : '';
4151
+ resultDataResponse.runBy = (_t = (_s = lastResultDetails === null || lastResultDetails === void 0 ? void 0 : lastResultDetails.runBy) === null || _s === void 0 ? void 0 : _s.displayName) !== null && _t !== void 0 ? _t : '';
4076
4152
  break;
4077
4153
  case 'executionDate':
4078
4154
  if (!(lastResultDetails === null || lastResultDetails === void 0 ? void 0 : lastResultDetails.dateCompleted)) {
4079
- logger_1.default.debug(`[RunResult] Missing dateCompleted for testCaseId=${String((_v = (_u = (_t = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _t === void 0 ? void 0 : _t.id) !== null && _u !== void 0 ? _u : point === null || point === void 0 ? void 0 : point.testCaseId) !== null && _v !== void 0 ? _v : 'unknown')} (lastRunId=${String(lastRunId !== null && lastRunId !== void 0 ? lastRunId : '')}, lastResultId=${String(lastResultId !== null && lastResultId !== void 0 ? lastResultId : '')}). lastResultDetails=${this.stringifyForDebug(lastResultDetails, 2000)}`);
4155
+ logger_1.default.debug(`[RunResult] Missing dateCompleted for testCaseId=${String((_w = (_v = (_u = resultData === null || resultData === void 0 ? void 0 : resultData.testCase) === null || _u === void 0 ? void 0 : _u.id) !== null && _v !== void 0 ? _v : point === null || point === void 0 ? void 0 : point.testCaseId) !== null && _w !== void 0 ? _w : 'unknown')} (lastRunId=${String(lastRunId !== null && lastRunId !== void 0 ? lastRunId : '')}, lastResultId=${String(lastResultId !== null && lastResultId !== void 0 ? lastResultId : '')}). lastResultDetails=${this.stringifyForDebug(lastResultDetails, 2000)}`);
4080
4156
  }
4081
- resultDataResponse.executionDate = (_w = lastResultDetails === null || lastResultDetails === void 0 ? void 0 : lastResultDetails.dateCompleted) !== null && _w !== void 0 ? _w : '';
4157
+ resultDataResponse.executionDate = (_x = lastResultDetails === null || lastResultDetails === void 0 ? void 0 : lastResultDetails.dateCompleted) !== null && _x !== void 0 ? _x : '';
4082
4158
  break;
4083
4159
  case 'configurationName':
4084
4160
  resultDataResponse.configurationName = configurationName;