@allurereport/plugin-awesome 3.16.1 → 3.17.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.
@@ -24,6 +24,8 @@ export const convertTestResult = (tr, options = {}) => {
24
24
  historyId: tr.historyId,
25
25
  flaky: tr.flaky,
26
26
  muted: tr.muted,
27
+ resolution: tr.resolution,
28
+ resolutionComment: tr.resolutionComment,
27
29
  isRetry: tr.isRetry,
28
30
  labels,
29
31
  groupedLabels: mapLabelsByName(labels),
@@ -1,4 +1,4 @@
1
- import { type AttachmentLink, type EnvironmentIdentity, type EnvironmentItem, type Statistic, type TestEnvGroup, type TestResult } from "@allurereport/core-api";
1
+ import { type AttachmentLink, type EnvironmentIdentity, type EnvironmentItem, 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";
@@ -14,12 +14,15 @@ export declare const getRunSummary: (testResults: Pick<TestResult, "start" | "st
14
14
  export declare const generateTree: (writer: AwesomeDataWriter, treeFilename: string, labels: string[], tests: ReportTestResult[], options?: {
15
15
  appendTitlePath?: boolean;
16
16
  }) => Promise<void>;
17
+ export declare const generateResolutionCategories: (writer: AwesomeDataWriter, tests: ReportTestResult[], filename?: string) => Promise<void>;
17
18
  export declare const generateEnvironmentJson: (writer: AwesomeDataWriter, env: EnvironmentItem[]) => Promise<void>;
18
19
  export declare const generateEnvirontmentsList: (writer: AwesomeDataWriter, store: AllureStore) => Promise<void>;
19
20
  export declare const generateVariables: (writer: AwesomeDataWriter, store: AllureStore) => Promise<void>;
20
21
  export declare const generateStatistic: (writer: AwesomeDataWriter, data: {
21
22
  stats: Statistic;
22
23
  statsByEnv: Map<string, Statistic>;
24
+ pieStats?: Statistic;
25
+ pieStatsByEnv?: Map<string, Statistic>;
23
26
  envs: EnvironmentIdentity[];
24
27
  }) => Promise<void>;
25
28
  export declare const generateAttachmentsFiles: (writer: AwesomeDataWriter, attachmentLinks: AttachmentLink[], contentFunction: (id: string) => Promise<ResultFile | undefined>) => Promise<Map<string, string>>;
@@ -48,4 +51,15 @@ export declare const generateStaticFiles: (payload: AwesomeOptions & {
48
51
  runSummary?: ReportRunSummary;
49
52
  }) => Promise<void>;
50
53
  export declare const generateAllCharts: (writer: AwesomeDataWriter, store: AllureStore, options: AwesomeOptions, context: PluginContext) => Promise<void>;
54
+ export type AwesomeMetricsWidget = {
55
+ current: MetricSample[];
56
+ history: {
57
+ uuid: string;
58
+ name: string;
59
+ timestamp: number;
60
+ url?: string;
61
+ metrics: Record<string, number>;
62
+ }[];
63
+ };
64
+ export declare const generateMetricsWidget: (writer: AwesomeDataWriter, store: AllureStore, reportUuid: string) => Promise<boolean>;
51
65
  export declare const generateTreeFilters: (writer: AwesomeDataWriter, testResults: ReportTestResult[]) => Promise<void>;
@@ -89,6 +89,7 @@ export const generateTestResults = async (_writer, store, trs, options = {}) =>
89
89
  const convertedTr = convertTestResult(tr, {
90
90
  hideLabels: options.hideLabels,
91
91
  });
92
+ const resolutionIssue = await store.resolutionIssueByTestResultId(tr.id);
92
93
  convertedTr.history = related.historyByTrId.get(tr.id) ?? [];
93
94
  convertedTr.retries = related.retriesByTrId.get(tr.id) ?? [];
94
95
  convertedTr.retriesCount = convertedTr.retries.length;
@@ -101,6 +102,7 @@ export const generateTestResults = async (_writer, store, trs, options = {}) =>
101
102
  type: "attachment",
102
103
  }));
103
104
  convertedTr.breadcrumbs = createBreadcrumbs(convertedTr);
105
+ convertedTr.resolutionIssue = resolutionIssue;
104
106
  convertedTrs.push(convertedTr);
105
107
  }
106
108
  convertedTrs = convertedTrs.sort(nullsLast(compareBy("start", ordinal()))).map((tr, idx) => ({
@@ -265,7 +267,7 @@ const buildTreeByTitlePath = (tests) => {
265
267
  };
266
268
  };
267
269
  const buildTreeByLabelsAndTitlePathCombined = (tests, labels) => collapseTreeGroups(createTreeByLabelsAndTitlePath(tests, labels, leafFactory, undefined, (group, leaf) => incrementStatistic(group.statistic, leaf.status)));
268
- const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesCount, transition, tooltips, historyId, groupedLabels, categories, }) => {
270
+ const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesCount, resolution, transition, tooltips, historyId, groupedLabels, categories, }) => {
269
271
  const leaf = {
270
272
  nodeId: id,
271
273
  id: historyId ?? id,
@@ -276,6 +278,7 @@ const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesC
276
278
  start,
277
279
  retry,
278
280
  retriesCount,
281
+ resolution,
279
282
  transition,
280
283
  tooltips,
281
284
  };
@@ -287,6 +290,53 @@ const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesC
287
290
  }
288
291
  return leaf;
289
292
  };
293
+ const resolutionOrder = ["issue", "muted", "accepted"];
294
+ const getResolutionGroupName = (test) => {
295
+ if (test.resolution === "issue") {
296
+ return test.resolutionIssue?.id ?? test.resolution;
297
+ }
298
+ return test.resolutionComment ?? test.resolution ?? "";
299
+ };
300
+ const resolutionTestResultFactory = (test, index) => ({
301
+ nodeId: test.id,
302
+ id: test.historyId ?? test.id,
303
+ name: test.name,
304
+ status: test.status,
305
+ duration: test.duration,
306
+ flaky: test.flaky,
307
+ transition: test.transition,
308
+ retry: test.retry,
309
+ retriesCount: test.retriesCount,
310
+ resolution: test.resolution,
311
+ groupOrder: index + 1,
312
+ tooltips: test.tooltips,
313
+ });
314
+ export const generateResolutionCategories = async (writer, tests, filename = "resolution-categories.json") => {
315
+ const groupsById = new Map();
316
+ tests
317
+ .filter((test) => !test.isRetry && test.resolution)
318
+ .forEach((test) => {
319
+ const resolution = test.resolution;
320
+ const groupId = resolution === "issue"
321
+ ? `${resolution}:${test.resolutionIssue?.id ?? test.id}`
322
+ : `${resolution}:${test.resolutionComment ?? test.id}`;
323
+ const group = groupsById.get(groupId) ?? {
324
+ id: groupId,
325
+ resolution,
326
+ name: getResolutionGroupName(test),
327
+ comment: test.resolutionComment ?? test.resolutionIssue?.comment,
328
+ issue: test.resolutionIssue,
329
+ testResults: [],
330
+ };
331
+ group.testResults.push(resolutionTestResultFactory(test, group.testResults.length));
332
+ groupsById.set(groupId, group);
333
+ });
334
+ const groups = [...groupsById.values()].sort((a, b) => {
335
+ const resolutionDiff = resolutionOrder.indexOf(a.resolution) - resolutionOrder.indexOf(b.resolution);
336
+ return resolutionDiff || a.name.localeCompare(b.name);
337
+ });
338
+ await writer.writeWidget(filename, { groups });
339
+ };
290
340
  export const generateEnvironmentJson = async (writer, env) => {
291
341
  await writer.writeWidget("allure_environment.json", env);
292
342
  };
@@ -304,16 +354,16 @@ export const generateVariables = async (writer, store) => {
304
354
  }
305
355
  };
306
356
  export const generateStatistic = async (writer, data) => {
307
- const { stats, statsByEnv, envs } = data;
357
+ const { stats, statsByEnv, pieStats = stats, pieStatsByEnv, envs } = data;
308
358
  await writer.writeWidget("statistic.json", stats);
309
- await writer.writeWidget("pie_chart.json", getPieChartValues(stats));
359
+ await writer.writeWidget("pie_chart.json", getPieChartValues(pieStats));
310
360
  for (const env of envs) {
311
361
  const envStats = statsByEnv.get(env.id);
312
362
  if (!envStats) {
313
363
  continue;
314
364
  }
315
365
  await writer.writeWidget(joinPosixPath(env.id, "statistic.json"), envStats);
316
- await writer.writeWidget(joinPosixPath(env.id, "pie_chart.json"), envStats);
366
+ await writer.writeWidget(joinPosixPath(env.id, "pie_chart.json"), getPieChartValues(pieStatsByEnv?.get(env.id) ?? envStats));
317
367
  }
318
368
  };
319
369
  export const generateAttachmentsFiles = async (writer, attachmentLinks, contentFunction) => {
@@ -402,7 +452,7 @@ export const generateStaticFiles = async (payload) => {
402
452
  const { manifest } = staticAssets;
403
453
  const headTags = [];
404
454
  const bodyTags = [];
405
- const sections = ["charts", "timeline"];
455
+ const sections = payload.sections?.length ? payload.sections : ["charts", "timeline"];
406
456
  if (!payload.singleFile) {
407
457
  for (const key in manifest) {
408
458
  const fileName = manifest[key];
@@ -478,6 +528,26 @@ export const generateAllCharts = async (writer, store, options, context) => {
478
528
  await writer.writeWidget("charts.json", generatedChartsData);
479
529
  }
480
530
  };
531
+ export const generateMetricsWidget = async (writer, store, reportUuid) => {
532
+ const current = await store.allMetrics();
533
+ if (current.length === 0) {
534
+ return false;
535
+ }
536
+ const history = (await store.allHistoryDataPoints())
537
+ .filter(({ uuid, metrics = {} }) => uuid !== reportUuid && Object.keys(metrics).length > 0)
538
+ .map(({ uuid, name, timestamp, url, metrics = {} }) => ({
539
+ uuid,
540
+ name,
541
+ timestamp,
542
+ ...(url ? { url } : {}),
543
+ metrics,
544
+ }));
545
+ await writer.writeWidget("metrics.json", {
546
+ current,
547
+ history,
548
+ });
549
+ return true;
550
+ };
481
551
  export const generateTreeFilters = async (writer, testResults) => {
482
552
  const trTags = new Set();
483
553
  const trCategories = new Set();
package/dist/plugin.js CHANGED
@@ -9,17 +9,31 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
- var _AwesomePlugin_writer, _AwesomePlugin_generate;
13
- import { incrementStatistic, joinPosixPath } from "@allurereport/core-api";
12
+ var _AwesomePlugin_writer, _AwesomePlugin_generateAfterStart, _AwesomePlugin_generate;
13
+ import { incrementStatistic, joinPosixPath, } from "@allurereport/core-api";
14
14
  import { createPluginSummary, } from "@allurereport/plugin-api";
15
15
  import { preciseTreeLabels } from "@allurereport/plugin-api";
16
16
  import { applyCategoriesToTestResults, generateCategories } from "./categories.js";
17
17
  import { generateTimeline } from "./generateTimeline.js";
18
- import { generateAllCharts, generateAttachmentsFiles, generateEnvironmentJson, generateEnvirontmentsList, generateGlobals, generateHistoryDataPoints, generateNav, generateQualityGateResults, generateSearchIndex, generateStaticFiles, generateStatistic, generateTestCases, generateTestEnvGroups, generateTestResults, generateTree, generateTreeFilters, generateVariables, getRunSummary, } from "./generators.js";
18
+ import { generateAllCharts, generateAttachmentsFiles, generateEnvironmentJson, generateEnvirontmentsList, generateGlobals, generateHistoryDataPoints, generateMetricsWidget, generateNav, generateQualityGateResults, generateResolutionCategories, generateSearchIndex, generateStaticFiles, generateStatistic, generateTestCases, generateTestEnvGroups, generateTestResults, generateTree, generateTreeFilters, generateVariables, getRunSummary, } from "./generators.js";
19
19
  import { InMemoryReportDataWriter, ReportFileDataWriter } from "./writer.js";
20
20
  const statisticByTestResults = async (store, testResults) => {
21
21
  const statistic = { total: 0 };
22
22
  const related = await store.relatedByTestResultIds(testResults.map(({ id }) => id));
23
+ const incrementResolution = (testResult) => {
24
+ if (testResult.resolution === "issue") {
25
+ statistic.resolutions ?? (statistic.resolutions = {});
26
+ statistic.resolutions.issues = (statistic.resolutions.issues ?? 0) + 1;
27
+ }
28
+ if (testResult.resolution === "muted") {
29
+ statistic.resolutions ?? (statistic.resolutions = {});
30
+ statistic.resolutions.muted = (statistic.resolutions.muted ?? 0) + 1;
31
+ }
32
+ if (testResult.resolution === "accepted") {
33
+ statistic.resolutions ?? (statistic.resolutions = {});
34
+ statistic.resolutions.accepted = (statistic.resolutions.accepted ?? 0) + 1;
35
+ }
36
+ };
23
37
  for (const testResult of testResults) {
24
38
  if (testResult.isRetry) {
25
39
  continue;
@@ -34,13 +48,21 @@ const statisticByTestResults = async (store, testResults) => {
34
48
  if (testResult.transition === "new") {
35
49
  statistic.new = (statistic.new ?? 0) + 1;
36
50
  }
51
+ incrementResolution(testResult);
37
52
  }
38
53
  return statistic;
39
54
  };
55
+ const isActiveStatisticTestResult = (testResult) => testResult.resolution !== "muted" && testResult.resolution !== "accepted";
40
56
  export class AwesomePlugin {
41
57
  constructor(options = {}) {
42
58
  this.options = options;
43
59
  _AwesomePlugin_writer.set(this, void 0);
60
+ _AwesomePlugin_generateAfterStart.set(this, async (context, store) => {
61
+ if (!__classPrivateFieldGet(this, _AwesomePlugin_writer, "f")) {
62
+ throw new Error("call start first");
63
+ }
64
+ await __classPrivateFieldGet(this, _AwesomePlugin_generate, "f").call(this, context, store);
65
+ });
44
66
  _AwesomePlugin_generate.set(this, async (context, store) => {
45
67
  const { singleFile, groupBy = [], filter, appendTitlePath } = this.options ?? {};
46
68
  const hideLabels = context.hideLabels;
@@ -53,6 +75,8 @@ export class AwesomePlugin {
53
75
  const statistics = await store.testsStatistic(filter);
54
76
  const environments = await store.allEnvironmentIdentities();
55
77
  const envStatistics = new Map();
78
+ const pieStatistics = await statisticByTestResults(store, allTrs.filter(isActiveStatisticTestResult));
79
+ const pieEnvStatistics = new Map();
56
80
  const allTestEnvGroups = await store.allTestEnvGroups();
57
81
  const globalAttachments = await store.allGlobalAttachments();
58
82
  const globalAttachmentsByEnv = await store.allGlobalAttachmentsByEnv();
@@ -83,14 +107,19 @@ export class AwesomePlugin {
83
107
  }
84
108
  }
85
109
  await Promise.all(environments.map(async ({ id }) => {
86
- envStatistics.set(id, await statisticByTestResults(store, trsByEnvId.get(id) ?? []));
110
+ const envTrs = trsByEnvId.get(id) ?? [];
111
+ envStatistics.set(id, await statisticByTestResults(store, envTrs));
112
+ pieEnvStatistics.set(id, await statisticByTestResults(store, envTrs.filter(isActiveStatisticTestResult)));
87
113
  }));
88
114
  await generateStatistic(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), {
89
115
  stats: statistics,
90
116
  statsByEnv: envStatistics,
117
+ pieStats: pieStatistics,
118
+ pieStatsByEnv: pieEnvStatistics,
91
119
  envs: environments,
92
120
  });
93
121
  await generateAllCharts(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, this.options, context);
122
+ const hasMetrics = await generateMetricsWidget(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, context.reportUuid);
94
123
  const convertedTrs = await generateTestResults(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, allTrs, { hideLabels });
95
124
  applyCategoriesToTestResults(convertedTrs, categories);
96
125
  await generateCategories(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), {
@@ -101,6 +130,7 @@ export class AwesomePlugin {
101
130
  defaultEnvironment: "default",
102
131
  selectedEnvironmentCount: environments.length,
103
132
  });
133
+ await generateResolutionCategories(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), convertedTrs);
104
134
  const hasGroupBy = groupBy.length > 0;
105
135
  await generateTimeline(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), allTrs, this.options, envIdByTrId);
106
136
  const treeLabels = hasGroupBy
@@ -131,6 +161,7 @@ export class AwesomePlugin {
131
161
  selectedEnvironmentCount: 1,
132
162
  filename: joinPosixPath(reportEnvironment.id, "categories.json"),
133
163
  });
164
+ await generateResolutionCategories(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), envConvertedTrs, joinPosixPath(reportEnvironment.id, "resolution-categories.json"));
134
165
  }
135
166
  await generateTreeFilters(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), convertedTrs);
136
167
  await generateEnvirontmentsList(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store);
@@ -153,8 +184,13 @@ export class AwesomePlugin {
153
184
  contentFunction: (id) => store.attachmentContentById(id),
154
185
  });
155
186
  const reportDataFiles = singleFile ? __classPrivateFieldGet(this, _AwesomePlugin_writer, "f").reportFiles() : [];
187
+ const configuredSections = this.options.sections ?? ["charts", "timeline"];
188
+ const sections = hasMetrics
189
+ ? [...new Set([...configuredSections, "metrics"])]
190
+ : configuredSections.filter((section) => section !== "metrics");
156
191
  await generateStaticFiles({
157
192
  ...this.options,
193
+ sections,
158
194
  id: context.id,
159
195
  allureVersion: context.allureVersion,
160
196
  reportFiles: context.reportFiles,
@@ -176,16 +212,10 @@ export class AwesomePlugin {
176
212
  await Promise.resolve();
177
213
  };
178
214
  this.update = async (context, store) => {
179
- if (!__classPrivateFieldGet(this, _AwesomePlugin_writer, "f")) {
180
- throw new Error("call start first");
181
- }
182
- await __classPrivateFieldGet(this, _AwesomePlugin_generate, "f").call(this, context, store);
215
+ await __classPrivateFieldGet(this, _AwesomePlugin_generateAfterStart, "f").call(this, context, store);
183
216
  };
184
217
  this.done = async (context, store) => {
185
- if (!__classPrivateFieldGet(this, _AwesomePlugin_writer, "f")) {
186
- throw new Error("call start first");
187
- }
188
- await __classPrivateFieldGet(this, _AwesomePlugin_generate, "f").call(this, context, store);
218
+ await __classPrivateFieldGet(this, _AwesomePlugin_generateAfterStart, "f").call(this, context, store);
189
219
  };
190
220
  }
191
221
  async info(context, store) {
@@ -204,4 +234,4 @@ export class AwesomePlugin {
204
234
  });
205
235
  }
206
236
  }
207
- _AwesomePlugin_writer = new WeakMap(), _AwesomePlugin_generate = new WeakMap();
237
+ _AwesomePlugin_writer = new WeakMap(), _AwesomePlugin_generateAfterStart = new WeakMap(), _AwesomePlugin_generate = new WeakMap();
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/plugin-awesome",
3
- "version": "3.16.1",
3
+ "version": "3.17.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.16.1",
34
- "@allurereport/core-api": "3.16.1",
35
- "@allurereport/plugin-api": "3.16.1",
36
- "@allurereport/web-commons": "3.16.1",
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",
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.16.1",
42
+ "@allurereport/web-awesome": "3.17.0",
43
43
  "@types/d3-shape": "^3.1.8",
44
44
  "@types/markdown-it": "^14.1.2",
45
45
  "@types/node": "^20",