From 85969254d7a2d97809da05ef02302325e9fc18b9 Mon Sep 17 00:00:00 2001 From: epszaw Date: Tue, 25 Nov 2025 11:40:22 +0100 Subject: [PATCH] add allure summary docs rename plugin summary to allure summary --- docs/summary.md | 103 ++++++++++++++++++++++++ packages/core/src/report.ts | 4 +- packages/plugin-allure2/src/plugin.ts | 4 +- packages/plugin-api/src/plugin.ts | 4 +- packages/plugin-awesome/src/plugin.ts | 4 +- packages/plugin-classic/src/plugin.ts | 4 +- packages/plugin-dashboard/src/plugin.ts | 4 +- packages/summary/src/generators.ts | 4 +- packages/summary/src/index.ts | 4 +- 9 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 docs/summary.md diff --git a/docs/summary.md b/docs/summary.md new file mode 100644 index 00000000000..6558a957d56 --- /dev/null +++ b/docs/summary.md @@ -0,0 +1,103 @@ +# Allure Summary + +**Allure Summary** provides a short overview of a plugin execution. It also can be used to represent any +test run data outside of Allure Report plugins, to make it compatible with the Allure ecosystem. + +Now, Allure Summary is utilized for the following purposes: + +- displaying plugins on the Allure Report Summary page +- producing output by [Allure Github Action](https://github.com/allure-framework/allure-action) +- building another kind of integration that may require brief test information + +## Structure of the Allure Summary + +```ts +// it's a short test result format that contains enough data to represent a test in the summary +export type SummaryTestResult = { + name: string; + id: string; + status: "passed" | "failed" | "broken" | "skipped" | "unknown"; + duration: number; +} + +export interface AllureSummary { + // link to the hosted report (for example, published to Allure Service) + remoteHref?: string; + // link to the job that produced the report (for example, CI job) + jobHref?: string; + // link to the pull request that triggered the job + pullRequestHref?: string; + // the report's name which displays on the summary page + name: string; + // overall statistics + stats: { + regressed?: number; + fixed?: number; + malfunctioned?: number; + new?: number; + failed?: number; + broken?: number; + passed?: number; + skipped?: number; + unknown?: number; + total: number; + retries?: number; + flaky?: number; + }; + // the worst test result status + status: "passed" | "failed" | "broken" | "skipped" | "unknown"; + // total test run duration in milliseconds + duration: number; + // the id of the plugin that generated the summary + plugin?: string; + // brief description of the test run + newTests?: SummaryTestResult[]; + flakyTests?: SummaryTestResult[]; + retryTests?: SummaryTestResult[]; + // date when the plugin generated the output + createdAt?: number; +} +``` + +## Displaying the plugin's summary information + +To make your plugin visible on the Allure Report Summary page or in the Allure GitHub action comment, you need to +Implement the `info` method in the plugin class that returns the `AllureSummary` object: + +```ts +import { getWorstStatus } from "@allurereport/core-api"; +import { + type AllureStore, + type Plugin, + type PluginContext, + type AllureSummary, +} from "@allurereport/plugin-api"; + +export class MyPlugin implements Plugin { + // ... + + // typical implementation of the info method + async info(context: PluginContext, store: AllureStore): Promise { + const allTrs = (await store.allTestResults()).filter((tr) => + this.options.filter ? this.options.filter(tr) : true, + ); + const newTrs = await store.allNewTestResults(); + const retryTrs = allTrs.filter((tr) => !!tr?.retries?.length); + const flakyTrs = allTrs.filter((tr) => !!tr?.flaky); + const duration = allTrs.reduce((acc, { duration: trDuration = 0 }) => acc + trDuration, 0); + const createdAt = allTrs.reduce((acc, { stop }) => Math.max(acc, stop || 0), 0); + + return { + plugin: "My plugin", + name: this.options.reportName || context.reportName, + stats: await store.testsStatistic(this.options.filter), + status: getWorstStatus(allTrs.map(({ status }) => status)) ?? "passed", + newTests: newTrs.map(convertToSummaryTestResult), + flakyTests: flakyTrs.map(convertToSummaryTestResult), + retryTests: retryTrs.map(convertToSummaryTestResult), + duration, + createdAt, + }; + } +} +``` diff --git a/packages/core/src/report.ts b/packages/core/src/report.ts index afc19135e1b..3150d444754 100644 --- a/packages/core/src/report.ts +++ b/packages/core/src/report.ts @@ -9,10 +9,10 @@ import type { import { type AllureStoreDump, AllureStoreDumpFiles, + type AllureSummary, type Plugin, type PluginContext, type PluginState, - type PluginSummary, type ReportFiles, type ResultFile, } from "@allurereport/plugin-api"; @@ -457,7 +457,7 @@ export class AllureReport { }; done = async (): Promise => { - const summaries: PluginSummary[] = []; + const summaries: AllureSummary[] = []; const remoteHrefs: string[] = []; if (this.#executionStage !== "running") { diff --git a/packages/plugin-allure2/src/plugin.ts b/packages/plugin-allure2/src/plugin.ts index 0bcb2e5bb54..a053e9aecdc 100644 --- a/packages/plugin-allure2/src/plugin.ts +++ b/packages/plugin-allure2/src/plugin.ts @@ -2,9 +2,9 @@ import type { EnvironmentItem } from "@allurereport/core-api"; import { getWorstStatus } from "@allurereport/core-api"; import { type AllureStore, + type AllureSummary, type Plugin, type PluginContext, - type PluginSummary, convertToSummaryTestResult, preciseTreeLabels, } from "@allurereport/plugin-api"; @@ -101,7 +101,7 @@ export class Allure2Plugin implements Plugin { }); }; - async info(context: PluginContext, store: AllureStore): Promise { + async info(context: PluginContext, store: AllureStore): Promise { const allTrs = await store.allTestResults(); const newTrs = await store.allNewTestResults(); const retryTrs = allTrs.filter((tr) => !!tr?.retries?.length); diff --git a/packages/plugin-api/src/plugin.ts b/packages/plugin-api/src/plugin.ts index 6caf20346a9..ff0a185c854 100644 --- a/packages/plugin-api/src/plugin.ts +++ b/packages/plugin-api/src/plugin.ts @@ -45,7 +45,7 @@ export interface PluginContext { */ export type SummaryTestResult = Pick; -export interface PluginSummary { +export interface AllureSummary { href?: string; remoteHref?: string; jobHref?: string; @@ -121,5 +121,5 @@ export interface Plugin { done?(context: PluginContext, store: AllureStore): Promise; - info?(context: PluginContext, store: AllureStore): Promise; + info?(context: PluginContext, store: AllureStore): Promise; } diff --git a/packages/plugin-awesome/src/plugin.ts b/packages/plugin-awesome/src/plugin.ts index 87214b93eca..7bb57e85f96 100644 --- a/packages/plugin-awesome/src/plugin.ts +++ b/packages/plugin-awesome/src/plugin.ts @@ -1,9 +1,9 @@ import { type EnvironmentItem, type Statistic, getWorstStatus } from "@allurereport/core-api"; import { type AllureStore, + type AllureSummary, type Plugin, type PluginContext, - type PluginSummary, convertToSummaryTestResult, } from "@allurereport/plugin-api"; import { preciseTreeLabels } from "@allurereport/plugin-api"; @@ -141,7 +141,7 @@ export class AwesomePlugin implements Plugin { await this.#generate(context, store); }; - async info(context: PluginContext, store: AllureStore): Promise { + async info(context: PluginContext, store: AllureStore): Promise { const allTrs = (await store.allTestResults()).filter((tr) => this.options.filter ? this.options.filter(tr) : true, ); diff --git a/packages/plugin-classic/src/plugin.ts b/packages/plugin-classic/src/plugin.ts index 400045a675b..b14e379c985 100644 --- a/packages/plugin-classic/src/plugin.ts +++ b/packages/plugin-classic/src/plugin.ts @@ -2,9 +2,9 @@ import type { EnvironmentItem } from "@allurereport/core-api"; import { getWorstStatus } from "@allurereport/core-api"; import { type AllureStore, + type AllureSummary, type Plugin, type PluginContext, - type PluginSummary, convertToSummaryTestResult, } from "@allurereport/plugin-api"; import { preciseTreeLabels } from "@allurereport/plugin-api"; @@ -108,7 +108,7 @@ export class ClassicPlugin implements Plugin { await this.#generate(context, store); }; - async info(context: PluginContext, store: AllureStore): Promise { + async info(context: PluginContext, store: AllureStore): Promise { const allTrs = (await store.allTestResults()).filter(this.options.filter ? this.options.filter : () => true); const newTrs = await store.allNewTestResults(); const retryTrs = allTrs.filter((tr) => !!tr?.retries?.length); diff --git a/packages/plugin-dashboard/src/plugin.ts b/packages/plugin-dashboard/src/plugin.ts index 8d247282784..59bade3bd32 100644 --- a/packages/plugin-dashboard/src/plugin.ts +++ b/packages/plugin-dashboard/src/plugin.ts @@ -1,9 +1,9 @@ import { getWorstStatus } from "@allurereport/core-api"; import { type AllureStore, + type AllureSummary, type Plugin, type PluginContext, - type PluginSummary, convertToSummaryTestResult, } from "@allurereport/plugin-api"; import { generateAllCharts, generateEnvirontmentsList, generateStaticFiles } from "./generators.js"; @@ -55,7 +55,7 @@ export class DashboardPlugin implements Plugin { await this.#generate(context, store); }; - async info(context: PluginContext, store: AllureStore): Promise { + async info(context: PluginContext, store: AllureStore): Promise { const allTrs = (await store.allTestResults()).filter(this.options.filter ? this.options.filter : () => true); const newTrs = await store.allNewTestResults(); const retryTrs = allTrs.filter((tr) => !!tr?.retries?.length); diff --git a/packages/summary/src/generators.ts b/packages/summary/src/generators.ts index 43c74dae66b..463258eba02 100644 --- a/packages/summary/src/generators.ts +++ b/packages/summary/src/generators.ts @@ -1,5 +1,5 @@ import { createBaseUrlScript, createScriptTag } from "@allurereport/core-api"; -import type { PluginSummary } from "@allurereport/plugin-api"; +import type { AllureSummary } from "@allurereport/plugin-api"; import Handlebars from "handlebars"; import { readFile } from "node:fs/promises"; import { createRequire } from "node:module"; @@ -37,7 +37,7 @@ export const readTemplateManifest = async (): Promise => { return JSON.parse(templateManifest); }; -export const generateSummaryStaticFiles = async (payload: { summaries: PluginSummary[] }) => { +export const generateSummaryStaticFiles = async (payload: { summaries: AllureSummary[] }) => { const compile = Handlebars.compile(template); const manifest = await readTemplateManifest(); const bodyTags: string[] = []; diff --git a/packages/summary/src/index.ts b/packages/summary/src/index.ts index 490bc001546..981046d8cab 100644 --- a/packages/summary/src/index.ts +++ b/packages/summary/src/index.ts @@ -1,4 +1,4 @@ -import type { PluginSummary } from "@allurereport/plugin-api"; +import type { AllureSummary } from "@allurereport/plugin-api"; import { writeFile } from "node:fs/promises"; import { resolve } from "node:path"; import { generateSummaryStaticFiles } from "./generators.js"; @@ -8,7 +8,7 @@ import { generateSummaryStaticFiles } from "./generators.js"; * @param output * @param summaries */ -export const generateSummary = async (output: string, summaries: PluginSummary[]) => { +export const generateSummary = async (output: string, summaries: AllureSummary[]) => { if (!summaries.length) { return undefined; }