@allurereport/plugin-awesome 3.17.0 → 3.19.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.
@@ -1,10 +1,12 @@
1
- import { EMPTY_VALUE, buildEnvironmentSortOrder, compareChildNodes, extractErrorMatchingData, findLastByLabelName, incrementStatistic, matchCategory, } from "@allurereport/core-api";
1
+ import { EMPTY_VALUE, buildEnvironmentSortOrder, calculateRetryHash, compareChildNodes, extractErrorMatchingData, findLastByLabelName, incrementStatistic, matchCategory, } from "@allurereport/core-api";
2
2
  import { md5 } from "@allurereport/plugin-api";
3
3
  const emptyStat = () => ({
4
4
  total: 0,
5
5
  });
6
6
  const msgKey = (m) => (m && m.trim().length ? m : EMPTY_VALUE);
7
7
  const envKey = (m) => (m && m.trim().length ? m : EMPTY_VALUE);
8
+ const environmentNeutralRetryHash = (testResult) => calculateRetryHash({ testCaseHash: testResult.testCaseHash, parametersHash: testResult.parametersHash }) ??
9
+ testResult.id;
8
10
  const formatEmptyValue = (key) => {
9
11
  if (key === "message") {
10
12
  return "No message";
@@ -98,11 +100,11 @@ const buildGroupLevels = (category, testResult, matchingData, environmentCount,
98
100
  }
99
101
  const groupEnvironments = computeGroupEnvironments(category, environmentCount, isSingleEnvironmentSelected);
100
102
  if (groupEnvironments) {
101
- const testKeyValue = testResult.historyId ?? testResult.id;
103
+ const testKeyValue = environmentNeutralRetryHash(testResult);
102
104
  const testDisplayName = testResult.name ?? testKeyValue;
103
105
  levels.push({
104
106
  type: "history",
105
- key: "historyId",
107
+ key: "retryHash",
106
108
  value: testKeyValue,
107
109
  name: testDisplayName,
108
110
  });
@@ -165,14 +167,14 @@ export const generateCategories = async (writer, { tests, categories, filename =
165
167
  let parentId = catId;
166
168
  for (const level of levels) {
167
169
  const levelId = `${level.type}:${md5(`${parentId}\n${level.key}\n${level.value}`)}`;
168
- const historyId = level.type === "history" ? level.value : undefined;
170
+ const retryHash = level.type === "history" ? level.value : undefined;
169
171
  duplicateChecker({
170
172
  id: levelId,
171
173
  type: level.type,
172
174
  name: level.name,
173
175
  key: level.key,
174
176
  value: level.value,
175
- historyId,
177
+ retryHash,
176
178
  statistic: emptyStat(),
177
179
  childrenIds: [],
178
180
  });
@@ -21,9 +21,13 @@ export const convertTestResult = (tr, options = {}) => {
21
21
  duration: tr.duration,
22
22
  status: tr.status,
23
23
  fullName: tr.fullName,
24
- historyId: tr.historyId,
24
+ retryHash: tr.retryHash,
25
+ testCaseHash: tr.testCaseHash,
26
+ parametersHash: tr.parametersHash,
27
+ environmentHash: tr.environmentHash,
25
28
  flaky: tr.flaky,
26
29
  muted: tr.muted,
30
+ known: tr.known,
27
31
  resolution: tr.resolution,
28
32
  resolutionComment: tr.resolutionComment,
29
33
  isRetry: tr.isRetry,
@@ -33,8 +37,8 @@ export const convertTestResult = (tr, options = {}) => {
33
37
  links: tr.links,
34
38
  steps: (tr.steps ?? []).map(convertTestStepResult),
35
39
  error: tr.error,
40
+ errors: tr.errors,
36
41
  testCase: tr.testCase,
37
- retryHash: tr.retryHash,
38
42
  descriptionHtml: tr.descriptionHtml ?? markdownToHtml(tr.description),
39
43
  environment: tr.environment,
40
44
  setup: [],
@@ -3,5 +3,5 @@ import type { AwesomeOptions } from "./model.js";
3
3
  type Writer = {
4
4
  writeWidget(fileName: string, data: any): Promise<void>;
5
5
  };
6
- export declare const generateTimeline: (writer: Writer, trs: TestResult[], options: AwesomeOptions, environmentIdByTrId: Map<string, string>) => Promise<void>;
6
+ export declare const generateTimeline: (writer: Writer, trs: TestResult[], options: AwesomeOptions, environmentIdByTrId: Map<string, string>, environmentNameById?: Map<string, string>) => Promise<void>;
7
7
  export {};
@@ -2,7 +2,7 @@ const DEFAULT_MIN_DURATION = 1;
2
2
  const DEFAULT_TIMELINE_OPTIONS = {
3
3
  minDuration: DEFAULT_MIN_DURATION,
4
4
  };
5
- export const generateTimeline = async (writer, trs, options, environmentIdByTrId) => {
5
+ export const generateTimeline = async (writer, trs, options, environmentIdByTrId, environmentNameById = new Map()) => {
6
6
  const { timeline = DEFAULT_TIMELINE_OPTIONS } = options;
7
7
  const { minDuration = DEFAULT_MIN_DURATION } = timeline;
8
8
  const result = [];
@@ -23,14 +23,14 @@ export const generateTimeline = async (writer, trs, options, environmentIdByTrId
23
23
  }
24
24
  result.push({
25
25
  id: test.id,
26
- historyId: test.historyId,
26
+ retryHash: test.retryHash,
27
27
  name: test.name,
28
28
  status: test.status,
29
29
  isRetry: test.isRetry,
30
30
  host,
31
31
  thread,
32
32
  environment: environmentIdByTrId.get(test.id) ?? test.environment,
33
- environmentName: test.environment,
33
+ environmentName: environmentNameById.get(test.environment ?? "") ?? test.environment,
34
34
  start: test.start,
35
35
  duration,
36
36
  });
@@ -1,10 +1,12 @@
1
- import { type AttachmentLink, type EnvironmentIdentity, type EnvironmentItem, type MetricSample, type Statistic, type TestEnvGroup, type TestResult } from "@allurereport/core-api";
1
+ import { type AttachmentLink, type EnvironmentIdentity, type EnvironmentItem, type HistoryTestResultUrlResolver, type MetricSample, type Statistic, type TestEnvGroup, type TestResult } from "@allurereport/core-api";
2
2
  import type { AllureStore, ReportExecutorInfo, ReportRunSummary, ReportTestResult, GlobalAttachmentLink, ExitCode, PluginContext, PluginGlobalError, QualityGateValidationResult, ReportFiles, ResultFile } from "@allurereport/plugin-api";
3
3
  import type { AwesomeOptions, TemplateManifest } from "./model.js";
4
4
  import type { AwesomeDataWriter, ReportFile } from "./writer.js";
5
5
  export declare const readTemplateManifest: (_singleFileMode?: boolean) => Promise<TemplateManifest>;
6
- export declare const generateTestResults: (_writer: AwesomeDataWriter, store: AllureStore, trs: TestResult[], options?: {
6
+ export declare const generateTestResults: (_writer: AwesomeDataWriter, store: AllureStore, trs: TestResult[], options: {
7
+ pluginId: string;
7
8
  hideLabels?: readonly (string | RegExp)[];
9
+ resolveHistoryUrl?: HistoryTestResultUrlResolver;
8
10
  }) => Promise<ReportTestResult[]>;
9
11
  export declare const generateTestCases: (writer: AwesomeDataWriter, trs: ReportTestResult[]) => Promise<void>;
10
12
  export declare const generateTestEnvGroups: (writer: AwesomeDataWriter, groups: TestEnvGroup[]) => Promise<void>;
@@ -49,6 +51,7 @@ export declare const generateStaticFiles: (payload: AwesomeOptions & {
49
51
  reportName: string;
50
52
  executor?: ReportExecutorInfo;
51
53
  runSummary?: ReportRunSummary;
54
+ runSummaryByEnv?: Record<string, ReportRunSummary>;
52
55
  }) => Promise<void>;
53
56
  export declare const generateAllCharts: (writer: AwesomeDataWriter, store: AllureStore, options: AwesomeOptions, context: PluginContext) => Promise<void>;
54
57
  export type AwesomeMetricsWidget = {
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { defaultChartsConfig } from "@allurereport/charts-api";
3
- import { appLoaderFaviconDataUri, appLoaderStyles, compareBy, createAppLoaderMarkup, createBaseUrlScript, createFaviconLinkTag, createFontLinkTag, createReportDataScript, stringifyForInlineScript, createScriptTag, createStylesLinkTag, incrementStatistic, joinPosixPath, nullsLast, ordinal, } from "@allurereport/core-api";
3
+ import { appLoaderFaviconDataUri, appLoaderStyles, compareBy, createAppLoaderMarkup, createBaseUrlScript, createFaviconLinkTag, createFontLinkTag, createReportDataScript, stringifyForInlineScript, createScriptTag, createStylesLinkTag, incrementStatistic, joinPosixPath, nullsLast, ordinal, severityLabelName, } from "@allurereport/core-api";
4
4
  import { collapseTreeGroups, createTreeByLabels, createTreeByLabelsAndTitlePath, createTreeByTitlePath, preciseTreeLabels, processTree, } from "@allurereport/plugin-api";
5
5
  import { copyReportStaticAssets, getReportStaticAsset, readReportStaticAssets, } from "@allurereport/plugin-api/static-assets";
6
6
  import { generateCharts, getPieChartValues } from "@allurereport/web-commons";
@@ -78,7 +78,7 @@ const writeConcurrently = async (items, write, concurrency = 64) => {
78
78
  await Promise.all(items.slice(i, i + concurrency).map(write));
79
79
  }
80
80
  };
81
- export const generateTestResults = async (_writer, store, trs, options = {}) => {
81
+ export const generateTestResults = async (_writer, store, trs, options) => {
82
82
  let convertedTrs = [];
83
83
  const related = await store.relatedByTestResultIds(trs.map(({ id }) => id));
84
84
  for (const tr of trs) {
@@ -90,7 +90,10 @@ export const generateTestResults = async (_writer, store, trs, options = {}) =>
90
90
  hideLabels: options.hideLabels,
91
91
  });
92
92
  const resolutionIssue = await store.resolutionIssueByTestResultId(tr.id);
93
- convertedTr.history = related.historyByTrId.get(tr.id) ?? [];
93
+ convertedTr.history = (related.historyByTrId.get(tr.id) ?? []).map((item) => ({
94
+ ...item,
95
+ url: options.resolveHistoryUrl?.(item.url, options.pluginId, item.id) ?? "",
96
+ }));
94
97
  convertedTr.retries = related.retriesByTrId.get(tr.id) ?? [];
95
98
  convertedTr.retriesCount = convertedTr.retries.length;
96
99
  convertedTr.retry = convertedTr.retriesCount > 0;
@@ -156,18 +159,21 @@ const searchDocumentFactory = (test) => {
156
159
  });
157
160
  const links = (test.links ?? []).flatMap(({ name, url, type }) => [name, url, type]);
158
161
  const categories = test.categories?.map((category) => category.name);
162
+ const statusMessages = (test.errors?.length ? test.errors : test.error ? [test.error] : [])
163
+ .map((error) => error.message)
164
+ .filter(Boolean);
159
165
  return {
160
166
  id: test.id,
161
167
  nodeId: test.id,
162
168
  name: test.name,
163
169
  fullName: test.fullName,
164
- historyId: test.historyId,
170
+ retryHash: test.retryHash,
165
171
  labels: joinSearchValues(labels),
166
172
  owner: joinSearchValues(test.groupedLabels.owner ?? []),
167
173
  tags: joinSearchValues(tags),
168
174
  parameters: joinSearchValues(parameters),
169
175
  categories: joinSearchValues(categories ?? []),
170
- statusMessage: test.error?.message,
176
+ statusMessage: joinSearchValues(statusMessages),
171
177
  links: joinSearchValues(links),
172
178
  };
173
179
  };
@@ -267,10 +273,10 @@ const buildTreeByTitlePath = (tests) => {
267
273
  };
268
274
  };
269
275
  const buildTreeByLabelsAndTitlePathCombined = (tests, labels) => collapseTreeGroups(createTreeByLabelsAndTitlePath(tests, labels, leafFactory, undefined, (group, leaf) => incrementStatistic(group.statistic, leaf.status)));
270
- const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesCount, resolution, transition, tooltips, historyId, groupedLabels, categories, }) => {
276
+ const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesCount, resolution, transition, tooltips, retryHash, groupedLabels, categories, }) => {
271
277
  const leaf = {
272
278
  nodeId: id,
273
- id: historyId ?? id,
279
+ id: retryHash ?? id,
274
280
  name,
275
281
  status,
276
282
  duration,
@@ -282,6 +288,10 @@ const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesC
282
288
  transition,
283
289
  tooltips,
284
290
  };
291
+ const severity = groupedLabels[severityLabelName]?.[0];
292
+ if (severity) {
293
+ leaf.severity = severity;
294
+ }
285
295
  if (groupedLabels.tag && groupedLabels.tag.length > 0) {
286
296
  leaf.tags = groupedLabels.tag;
287
297
  }
@@ -299,7 +309,7 @@ const getResolutionGroupName = (test) => {
299
309
  };
300
310
  const resolutionTestResultFactory = (test, index) => ({
301
311
  nodeId: test.id,
302
- id: test.historyId ?? test.id,
312
+ id: test.retryHash ?? test.id,
303
313
  name: test.name,
304
314
  status: test.status,
305
315
  duration: test.duration,
@@ -447,7 +457,7 @@ export const generateQualityGateResults = async (writer, qualityGateResults = {}
447
457
  await writer.writeWidget("quality-gate.json", resultsWithTrees);
448
458
  };
449
459
  export const generateStaticFiles = async (payload) => {
450
- const { id, reportName = "Allure Report", reportLanguage = "en", logo = "", theme = "auto", groupBy, reportFiles, reportDataFiles, reportUuid, allureVersion, layout = "base", defaultSection = "", ci, executor, runSummary, stepTreeExpansion, defaultSortBy, } = payload;
460
+ const { id, reportName = "Allure Report", reportLanguage = "en", logo = "", theme = "auto", groupBy, reportFiles, reportDataFiles, reportUuid, allureVersion, layout = "base", defaultSection = "", ci, executor, runSummary, runSummaryByEnv, stepTreeExpansion, defaultSortBy, } = payload;
451
461
  const staticAssets = await readReportStaticAssets(reportStaticArchive);
452
462
  const { manifest } = staticAssets;
453
463
  const headTags = [];
@@ -492,6 +502,7 @@ export const generateStaticFiles = async (payload) => {
492
502
  ci,
493
503
  executor,
494
504
  runSummary,
505
+ runSummaryByEnv,
495
506
  layout,
496
507
  allureVersion,
497
508
  sections,
package/dist/plugin.js CHANGED
@@ -111,6 +111,13 @@ export class AwesomePlugin {
111
111
  envStatistics.set(id, await statisticByTestResults(store, envTrs));
112
112
  pieEnvStatistics.set(id, await statisticByTestResults(store, envTrs.filter(isActiveStatisticTestResult)));
113
113
  }));
114
+ const runSummaryByEnv = {};
115
+ for (const { id } of environments) {
116
+ const envRunSummary = getRunSummary(trsByEnvId.get(id) ?? []);
117
+ if (envRunSummary) {
118
+ runSummaryByEnv[id] = envRunSummary;
119
+ }
120
+ }
114
121
  await generateStatistic(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), {
115
122
  stats: statistics,
116
123
  statsByEnv: envStatistics,
@@ -120,19 +127,23 @@ export class AwesomePlugin {
120
127
  });
121
128
  await generateAllCharts(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, this.options, context);
122
129
  const hasMetrics = await generateMetricsWidget(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, context.reportUuid);
123
- const convertedTrs = await generateTestResults(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, allTrs, { hideLabels });
130
+ const convertedTrs = await generateTestResults(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, allTrs, {
131
+ pluginId: context.id,
132
+ hideLabels,
133
+ resolveHistoryUrl: context.history?.resolveTestResultUrl,
134
+ });
124
135
  applyCategoriesToTestResults(convertedTrs, categories);
125
136
  await generateCategories(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), {
126
137
  tests: convertedTrs,
127
138
  categories,
128
139
  environmentCount: environments.length,
129
- environments: environments.map(({ name }) => name),
140
+ environments: environments.map(({ id }) => id),
130
141
  defaultEnvironment: "default",
131
142
  selectedEnvironmentCount: environments.length,
132
143
  });
133
144
  await generateResolutionCategories(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), convertedTrs);
134
145
  const hasGroupBy = groupBy.length > 0;
135
- await generateTimeline(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), allTrs, this.options, envIdByTrId);
146
+ await generateTimeline(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), allTrs, this.options, envIdByTrId, new Map(environments.map(({ id, name }) => [id, name])));
136
147
  const treeLabels = hasGroupBy
137
148
  ? preciseTreeLabels(groupBy, convertedTrs, ({ labels }) => labels.map(({ name }) => name))
138
149
  : [];
@@ -199,6 +210,7 @@ export class AwesomePlugin {
199
210
  ci: context.ci,
200
211
  executor,
201
212
  runSummary,
213
+ runSummaryByEnv,
202
214
  reportDataFiles,
203
215
  });
204
216
  });
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/plugin-awesome",
3
- "version": "3.17.0",
3
+ "version": "3.19.0",
4
4
  "description": "Allure Awesome Plugin – brand new HTML report with modern design and new features",
5
5
  "keywords": [
6
6
  "allure",
@@ -30,16 +30,16 @@
30
30
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
31
31
  },
32
32
  "dependencies": {
33
- "@allurereport/charts-api": "3.17.0",
34
- "@allurereport/core-api": "3.17.0",
35
- "@allurereport/plugin-api": "3.17.0",
36
- "@allurereport/web-commons": "3.17.0",
33
+ "@allurereport/charts-api": "3.19.0",
34
+ "@allurereport/core-api": "3.19.0",
35
+ "@allurereport/plugin-api": "3.19.0",
36
+ "@allurereport/web-commons": "3.19.0",
37
37
  "d3-shape": "^3.2.0",
38
38
  "handlebars": "^4.7.9",
39
39
  "markdown-it": "^14.2.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@allurereport/web-awesome": "3.17.0",
42
+ "@allurereport/web-awesome": "3.19.0",
43
43
  "@types/d3-shape": "^3.1.8",
44
44
  "@types/markdown-it": "^14.1.2",
45
45
  "@types/node": "^20",