From 5eb5d585161b84533014c1b3f352d987c9a53aeb Mon Sep 17 00:00:00 2001 From: Dmitrii Evreinov Date: Thu, 3 Sep 2026 13:40:56 +0400 Subject: [PATCH] add resolution counters to summary stats --- packages/core-api/src/aggregate.ts | 3 ++ packages/core/src/store/store.ts | 15 +++++++ packages/core/test/store/store.test.ts | 50 +++++++++++++++++++++ packages/plugin-api/test/summary.test.ts | 2 +- packages/plugin-awesome/src/plugin.ts | 15 +++++++ packages/plugin-awesome/test/plugin.test.ts | 31 ++++++++++--- 6 files changed, 109 insertions(+), 7 deletions(-) diff --git a/packages/core-api/src/aggregate.ts b/packages/core-api/src/aggregate.ts index 298d7c15f02..a1c8cf41c71 100644 --- a/packages/core-api/src/aggregate.ts +++ b/packages/core-api/src/aggregate.ts @@ -14,4 +14,7 @@ export type Statistic = DiffStatistic & { total: number; retries?: number; flaky?: number; + resolutionIssue?: number; + resolutionMuted?: number; + resolutionAccepted?: number; }; diff --git a/packages/core/src/store/store.ts b/packages/core/src/store/store.ts index dadd354d10b..3167f4aafad 100644 --- a/packages/core/src/store/store.ts +++ b/packages/core/src/store/store.ts @@ -1355,6 +1355,19 @@ export class DefaultAllureStore implements AllureStore, ResultsVisitor { async testsStatistic(filter?: TestResultFilter) { const statistic: Statistic = { total: 0 }; + const incrementResolution = (tr: TestResult) => { + if (tr.resolution === "issue") { + statistic.resolutionIssue = (statistic.resolutionIssue ?? 0) + 1; + } + + if (tr.resolution === "muted") { + statistic.resolutionMuted = (statistic.resolutionMuted ?? 0) + 1; + } + + if (tr.resolution === "accepted") { + statistic.resolutionAccepted = (statistic.resolutionAccepted ?? 0) + 1; + } + }; for (const [, tr] of this.#testResults) { if (tr.isRetry) { @@ -1381,6 +1394,8 @@ export class DefaultAllureStore implements AllureStore, ResultsVisitor { statistic.new = (statistic.new ?? 0) + 1; } + incrementResolution(tr); + if (!statistic[tr.status]) { statistic[tr.status] = 0; } diff --git a/packages/core/test/store/store.test.ts b/packages/core/test/store/store.test.ts index 443b8134898..67d02bfc199 100644 --- a/packages/core/test/store/store.test.ts +++ b/packages/core/test/store/store.test.ts @@ -357,6 +357,56 @@ describe("test results", () => { await expect(target.testResultsByResolutionIssueId("SHOP-1")).resolves.toEqual([]); }); + it("should include resolution counters in test statistics", async () => { + const store = new DefaultAllureStore({ + resolutionsConfig: { + links: { jira: { urlTemplate: "https://example.org/%s" } }, + rules: [ + { + resolution: "issue", + issue: { id: "SHOP-1", type: "jira" }, + testCaseId: [md5("tc-issue")], + }, + { + resolution: "muted", + comment: "muted failure", + testCaseId: [md5("tc-muted")], + }, + { + resolution: "accepted", + comment: "accepted failure", + testCaseId: [md5("tc-accepted")], + }, + ], + }, + }); + + await store.visitTestResult( + { name: "issue latest", status: "failed", testId: "tc-issue", start: 1000 }, + { readerId }, + ); + await store.visitTestResult({ name: "issue retry", status: "failed", testId: "tc-issue", start: 0 }, { readerId }); + await store.visitTestResult({ name: "muted", status: "broken", testId: "tc-muted" }, { readerId }); + await store.visitTestResult({ name: "accepted", status: "failed", testId: "tc-accepted" }, { readerId }); + await store.visitTestResult({ name: "passed", status: "passed", testId: "tc-passed" }, { readerId }); + + await expect(store.testsStatistic()).resolves.toMatchObject({ + total: 4, + failed: 2, + broken: 1, + passed: 1, + resolutionIssue: 1, + resolutionMuted: 1, + resolutionAccepted: 1, + }); + await expect(store.testsStatistic((tr) => tr.status === "failed")).resolves.toMatchObject({ + total: 2, + failed: 2, + resolutionIssue: 1, + resolutionAccepted: 1, + }); + }); + it("should mark retries as isRetry", async () => { const store = new DefaultAllureStore(); const tr1: RawTestResult = { diff --git a/packages/plugin-api/test/summary.test.ts b/packages/plugin-api/test/summary.test.ts index fae9d369ed2..ea4ed55e3c5 100644 --- a/packages/plugin-api/test/summary.test.ts +++ b/packages/plugin-api/test/summary.test.ts @@ -80,7 +80,7 @@ describe("summary utils", () => { testResult({ id: "n1", name: "new", status: "passed", duration: 7 }), testResult({ id: "n2", name: "new-2", status: "failed", duration: 9 }), ]; - const stats = { total: 3 } as any; + const stats = { total: 3, resolutionIssue: 1, resolutionMuted: 1, resolutionAccepted: 1 } as any; const historyReadHistory = vi.fn().mockResolvedValue([{ branch: "main" }]); const history = { readHistory: historyReadHistory } as unknown as AllureHistory; const store = { diff --git a/packages/plugin-awesome/src/plugin.ts b/packages/plugin-awesome/src/plugin.ts index 1042f975626..47710de7fe6 100644 --- a/packages/plugin-awesome/src/plugin.ts +++ b/packages/plugin-awesome/src/plugin.ts @@ -40,6 +40,19 @@ const statisticByTestResults = async ( ): Promise => { const statistic: Statistic = { total: 0 }; const related = await store.relatedByTestResultIds(testResults.map(({ id }) => id)); + const incrementResolution = (testResult: (typeof testResults)[number]) => { + if (testResult.resolution === "issue") { + statistic.resolutionIssue = (statistic.resolutionIssue ?? 0) + 1; + } + + if (testResult.resolution === "muted") { + statistic.resolutionMuted = (statistic.resolutionMuted ?? 0) + 1; + } + + if (testResult.resolution === "accepted") { + statistic.resolutionAccepted = (statistic.resolutionAccepted ?? 0) + 1; + } + }; for (const testResult of testResults) { if (testResult.isRetry) { @@ -59,6 +72,8 @@ const statisticByTestResults = async ( if (testResult.transition === "new") { statistic.new = (statistic.new ?? 0) + 1; } + + incrementResolution(testResult); } return statistic; diff --git a/packages/plugin-awesome/test/plugin.test.ts b/packages/plugin-awesome/test/plugin.test.ts index fdf3db92088..a91b7117e97 100644 --- a/packages/plugin-awesome/test/plugin.test.ts +++ b/packages/plugin-awesome/test/plugin.test.ts @@ -21,7 +21,7 @@ const require = createRequire(import.meta.url); // duplicated the code from core to avoid circular dependency export const getTestResultsStats = (trs: TestResult[], filter: (tr: TestResult) => boolean = () => true) => { - const trsToProcess = trs.filter(filter); + const trsToProcess = trs.filter((tr) => !tr.isRetry && filter(tr)); return trsToProcess.reduce( (acc, test) => { @@ -31,6 +31,18 @@ export const getTestResultsStats = (trs: TestResult[], filter: (tr: TestResult) acc[test.status]!++; + if (test.resolution === "issue") { + acc.resolutionIssue = (acc.resolutionIssue ?? 0) + 1; + } + + if (test.resolution === "muted") { + acc.resolutionMuted = (acc.resolutionMuted ?? 0) + 1; + } + + if (test.resolution === "accepted") { + acc.resolutionAccepted = (acc.resolutionAccepted ?? 0) + 1; + } + return acc; }, { total: trsToProcess.length } as Statistic, @@ -413,7 +425,8 @@ describe("plugin", () => { const stagingTestResult = { id: "tr-staging", name: "staging test", - status: "passed", + status: "failed", + resolution: "accepted", environment: "staging", labels: [], parameters: [], @@ -494,11 +507,13 @@ describe("plugin", () => { expect(JSON.parse(addedFiles.get("widgets/statistic.json")!.toString("utf-8"))).toEqual({ total: 1, - passed: 1, + failed: 1, + resolutionAccepted: 1, }); expect(JSON.parse(addedFiles.get("widgets/staging/statistic.json")!.toString("utf-8"))).toEqual({ total: 1, - passed: 1, + failed: 1, + resolutionAccepted: 1, }); expect(JSON.parse(addedFiles.get("widgets/default/statistic.json")!.toString("utf-8"))).toEqual({ total: 0, @@ -519,7 +534,8 @@ describe("plugin", () => { const qaATestResult = { id: "tr-qa-a", name: "qa a test", - status: "passed", + status: "broken", + resolution: "muted", environment: "QA", labels: [], parameters: [], @@ -532,6 +548,7 @@ describe("plugin", () => { id: "tr-qa-b", name: "qa b test", status: "failed", + resolution: "issue", environment: "QA", labels: [], parameters: [], @@ -620,11 +637,13 @@ describe("plugin", () => { ]); expect(JSON.parse(addedFiles.get("widgets/qa_a/statistic.json")!.toString("utf-8"))).toEqual({ total: 1, - passed: 1, + broken: 1, + resolutionMuted: 1, }); expect(JSON.parse(addedFiles.get("widgets/qa_b/statistic.json")!.toString("utf-8"))).toEqual({ total: 1, failed: 1, + resolutionIssue: 1, }); expect(store.environmentIdByTrId).toHaveBeenCalledWith("tr-qa-a"); expect(store.environmentIdByTrId).toHaveBeenCalledWith("tr-qa-b");