@allurereport/plugin-awesome 3.20.0 → 3.20.1

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,11 +1,12 @@
1
1
  import { type AttachmentLink, type EnvironmentIdentity, type EnvironmentItem, type HistoryTestResultUrlResolver, type MetricSample, type Statistic, type TestEnvGroup, type TestResult } from "@allurereport/core-api";
2
- import type { AllureStore, ReportExecutorInfo, ReportRunSummary, ReportTestResult, GlobalAttachmentLink, ExitCode, PluginContext, PluginGlobalError, QualityGateValidationResult, ReportFiles, ResultFile } from "@allurereport/plugin-api";
2
+ import type { AllureStore, ReportExecutorInfo, ReportRunSummary, ReportTestResult, GlobalAttachmentLink, ExitCode, PluginContext, PluginGlobalError, QualityGateValidationResult, ReportFiles, ResultFile, TestResultRelatedData } 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
6
  export declare const generateTestResults: (_writer: AwesomeDataWriter, store: AllureStore, trs: TestResult[], options: {
7
7
  pluginId: string;
8
8
  hideLabels?: readonly (string | RegExp)[];
9
+ related?: TestResultRelatedData;
9
10
  resolveHistoryUrl?: HistoryTestResultUrlResolver;
10
11
  }) => Promise<ReportTestResult[]>;
11
12
  export declare const generateTestCases: (writer: AwesomeDataWriter, trs: ReportTestResult[]) => Promise<void>;
@@ -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, severityLabelName, } from "@allurereport/core-api";
3
+ import { appLoaderFaviconDataUri, appLoaderStyles, compareBy, createAppLoaderMarkup, createBaseUrlScript, createFaviconLinkTag, createFontLinkTag, createReportDataScript, stringifyForInlineScript, createScriptTag, createStylesLinkTag, incrementStatistic, joinPosixPath, nullsLast, ordinal, redactParameters, 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,9 +78,17 @@ const writeConcurrently = async (items, write, concurrency = 64) => {
78
78
  await Promise.all(items.slice(i, i + concurrency).map(write));
79
79
  }
80
80
  };
81
+ const mapConcurrently = async (items, map, concurrency = 8) => {
82
+ const results = [];
83
+ for (let i = 0; i < items.length; i += concurrency) {
84
+ results.push(...(await Promise.all(items.slice(i, i + concurrency).map(map))));
85
+ }
86
+ return results;
87
+ };
81
88
  export const generateTestResults = async (_writer, store, trs, options) => {
82
89
  let convertedTrs = [];
83
- const related = await store.relatedByTestResultIds(trs.map(({ id }) => id));
90
+ const related = options.related ?? (await store.relatedByTestResultIds(trs.map(({ id }) => id)));
91
+ const resolutionIssuesByTrId = related.resolutionIssuesByTrId;
84
92
  for (const tr of trs) {
85
93
  const trFixtures = related.fixturesByTrId.get(tr.id) ?? [];
86
94
  const convertedTrFixtures = [...trFixtures]
@@ -89,7 +97,6 @@ export const generateTestResults = async (_writer, store, trs, options) => {
89
97
  const convertedTr = convertTestResult(tr, {
90
98
  hideLabels: options.hideLabels,
91
99
  });
92
- const resolutionIssue = await store.resolutionIssueByTestResultId(tr.id);
93
100
  convertedTr.history = (related.historyByTrId.get(tr.id) ?? []).map((item) => ({
94
101
  ...item,
95
102
  url: options.resolveHistoryUrl?.(item.url, options.pluginId, item.id) ?? "",
@@ -105,7 +112,9 @@ export const generateTestResults = async (_writer, store, trs, options) => {
105
112
  type: "attachment",
106
113
  }));
107
114
  convertedTr.breadcrumbs = createBreadcrumbs(convertedTr);
108
- convertedTr.resolutionIssue = resolutionIssue;
115
+ convertedTr.resolutionIssue = resolutionIssuesByTrId
116
+ ? resolutionIssuesByTrId.get(tr.id)
117
+ : await store.resolutionIssueByTestResultId(tr.id);
109
118
  convertedTrs.push(convertedTr);
110
119
  }
111
120
  convertedTrs = convertedTrs.sort(nullsLast(compareBy("start", ordinal()))).map((tr, idx) => ({
@@ -273,8 +282,9 @@ const buildTreeByTitlePath = (tests) => {
273
282
  };
274
283
  };
275
284
  const buildTreeByLabelsAndTitlePathCombined = (tests, labels) => collapseTreeGroups(createTreeByLabelsAndTitlePath(tests, labels, leafFactory, undefined, (group, leaf) => incrementStatistic(group.statistic, leaf.status)));
276
- const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesCount, resolution, transition, tooltips, retryHash, groupedLabels, categories, }) => {
285
+ const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesCount, resolution, transition, tooltips, retryHash, groupedLabels, categories, parameters, }) => {
277
286
  const unresolvedFailure = (status === "failed" || status === "broken") && !resolution;
287
+ const parameterValues = redactParameters(parameters).flatMap(({ value }) => (value ? [value] : []));
278
288
  const leaf = {
279
289
  nodeId: id,
280
290
  id: retryHash ?? id,
@@ -290,6 +300,9 @@ const leafFactory = ({ id, name, status, duration, flaky, start, retry, retriesC
290
300
  transition,
291
301
  tooltips,
292
302
  };
303
+ if (parameterValues.length) {
304
+ leaf.parameters = parameterValues;
305
+ }
293
306
  const severity = groupedLabels[severityLabelName]?.[0];
294
307
  if (severity) {
295
308
  leaf.severity = severity;
@@ -379,20 +392,19 @@ export const generateStatistic = async (writer, data) => {
379
392
  }
380
393
  };
381
394
  export const generateAttachmentsFiles = async (writer, attachmentLinks, contentFunction) => {
382
- const result = new Map();
383
- for (const { id, ext, ...link } of attachmentLinks) {
395
+ const writtenAttachments = await mapConcurrently(attachmentLinks, async ({ id, ext, ...link }) => {
384
396
  if (link.missed) {
385
- continue;
397
+ return;
386
398
  }
387
399
  const content = await contentFunction(id);
388
400
  if (!content) {
389
- continue;
401
+ return;
390
402
  }
391
403
  const src = `${id}${ext}`;
392
404
  await writer.writeAttachment(src, content);
393
- result.set(id, src);
394
- }
395
- return result;
405
+ return [id, src];
406
+ });
407
+ return new Map(writtenAttachments.filter((attachment) => attachment !== undefined));
396
408
  };
397
409
  export const generateHistoryDataPoints = async (writer, store) => {
398
410
  const result = new Map();
@@ -413,15 +425,22 @@ export const generateGlobals = async (writer, payload) => {
413
425
  if (globalExitCode) {
414
426
  globals.exitCode = globalExitCode;
415
427
  }
416
- for (const attachment of globalAttachments) {
428
+ const attachmentWrites = new Map();
429
+ const writtenAttachments = await mapConcurrently(globalAttachments, async (attachment) => {
417
430
  const src = `${attachment.id}${attachment.ext}`;
418
431
  const content = await contentFunction(attachment.id);
419
432
  if (!content) {
420
- continue;
433
+ return;
421
434
  }
422
- await writer.writeAttachment(src, content);
423
- globals.attachments.push(attachment);
424
- }
435
+ let write = attachmentWrites.get(src);
436
+ if (!write) {
437
+ write = writer.writeAttachment(src, content);
438
+ attachmentWrites.set(src, write);
439
+ }
440
+ await write;
441
+ return attachment;
442
+ });
443
+ globals.attachments = writtenAttachments.filter((attachment) => attachment !== undefined);
425
444
  Object.entries(globalAttachmentsByEnv).forEach(([environmentId, attachments]) => {
426
445
  const attachmentIds = new Set(globals.attachments.map(({ id }) => id));
427
446
  const writtenAttachments = attachments.filter(({ id }) => attachmentIds.has(id));
package/dist/plugin.js CHANGED
@@ -10,16 +10,15 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
12
  var _AwesomePlugin_writer, _AwesomePlugin_generateAfterStart, _AwesomePlugin_generate;
13
- import { incrementStatistic, joinPosixPath, } from "@allurereport/core-api";
13
+ import { incrementStatistic, validateEnvironmentId, 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
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
- const statisticByTestResults = async (store, testResults) => {
20
+ const statisticByTestResults = (testResults, trIdsWithRetries) => {
21
21
  const statistic = { total: 0 };
22
- const related = await store.relatedByTestResultIds(testResults.map(({ id }) => id));
23
22
  const incrementResolution = (testResult) => {
24
23
  if (testResult.resolution === "issue") {
25
24
  statistic.resolutions ?? (statistic.resolutions = {});
@@ -39,7 +38,7 @@ const statisticByTestResults = async (store, testResults) => {
39
38
  continue;
40
39
  }
41
40
  incrementStatistic(statistic, testResult.status);
42
- if ((related.retriesByTrId.get(testResult.id)?.length ?? 0) > 0) {
41
+ if (trIdsWithRetries.has(testResult.id)) {
43
42
  statistic.retries = (statistic.retries ?? 0) + 1;
44
43
  }
45
44
  if (testResult.flaky) {
@@ -69,13 +68,15 @@ export class AwesomePlugin {
69
68
  const measure = (name, fn) => perf?.measure(name, fn) ?? fn();
70
69
  const hideLabels = context.hideLabels;
71
70
  const categories = context.categories ?? [];
72
- const { environmentItems, executor, attachments, allTrs, runSummary, statistics, environments, allTestEnvGroups, globalAttachments, globalAttachmentsByEnv, globalExitCode, globalErrors, globalErrorsByEnv, qualityGateResults, } = await measure("readData", async () => {
71
+ const { environmentItems, executor, attachments, allTrs, related, runSummary, statistics, environments, allTestEnvGroups, globalAttachments, globalAttachmentsByEnv, globalExitCode, globalErrors, globalErrorsByEnv, qualityGateResults, } = await measure("readData", async () => {
73
72
  const testResults = await store.allTestResults({ includeRetries: true, filter });
73
+ const relatedData = await store.relatedByTestResultIds(testResults.map(({ id }) => id));
74
74
  return {
75
75
  environmentItems: await store.metadataByKey("allure_environment"),
76
76
  executor: await store.metadataByKey("allure2_executor"),
77
77
  attachments: await store.allAttachments(),
78
78
  allTrs: testResults,
79
+ related: relatedData,
79
80
  runSummary: getRunSummary(testResults),
80
81
  statistics: await store.testsStatistic(filter),
81
82
  environments: await store.allEnvironmentIdentities(),
@@ -116,9 +117,15 @@ export class AwesomePlugin {
116
117
  });
117
118
  const trsByEnvId = new Map();
118
119
  await measure("stats", async () => {
120
+ const trIdsWithRetries = new Set();
119
121
  const envStatistics = new Map();
120
- const pieStatistics = await statisticByTestResults(store, allTrs.filter(isActiveStatisticTestResult));
121
122
  const pieEnvStatistics = new Map();
123
+ related.retriesByTrId.forEach((retries, trId) => {
124
+ if (retries.length > 0) {
125
+ trIdsWithRetries.add(trId);
126
+ }
127
+ });
128
+ const pieStatistics = statisticByTestResults(allTrs.filter(isActiveStatisticTestResult), trIdsWithRetries);
122
129
  for (const tr of allTrs) {
123
130
  const environmentId = envIdByTrId.get(tr.id);
124
131
  if (!environmentId) {
@@ -134,8 +141,8 @@ export class AwesomePlugin {
134
141
  }
135
142
  await Promise.all(environments.map(async ({ id }) => {
136
143
  const envTrs = trsByEnvId.get(id) ?? [];
137
- envStatistics.set(id, await statisticByTestResults(store, envTrs));
138
- pieEnvStatistics.set(id, await statisticByTestResults(store, envTrs.filter(isActiveStatisticTestResult)));
144
+ envStatistics.set(id, statisticByTestResults(envTrs, trIdsWithRetries));
145
+ pieEnvStatistics.set(id, statisticByTestResults(envTrs.filter(isActiveStatisticTestResult), trIdsWithRetries));
139
146
  }));
140
147
  await generateStatistic(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), {
141
148
  stats: statistics,
@@ -157,6 +164,7 @@ export class AwesomePlugin {
157
164
  const convertedTrs = await measure("convert", () => generateTestResults(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, allTrs, {
158
165
  pluginId: context.id,
159
166
  hideLabels,
167
+ related,
160
168
  resolveHistoryUrl: context.history?.resolveTestResultUrl,
161
169
  }));
162
170
  if (perf) {
@@ -194,7 +202,11 @@ export class AwesomePlugin {
194
202
  const convertedTrsById = new Map(convertedTrs.map((tr) => [tr.id, tr]));
195
203
  await measure("environmentsOutput", async () => {
196
204
  for (const reportEnvironment of environments) {
197
- const envTrs = await store.testResultsByEnvironmentId(reportEnvironment.id, { includeRetries: true });
205
+ const environmentIdValidation = validateEnvironmentId(reportEnvironment.id);
206
+ if (!environmentIdValidation.valid) {
207
+ throw new Error(`Invalid environmentId ${JSON.stringify(reportEnvironment.id)}: ${environmentIdValidation.reason}`);
208
+ }
209
+ const envTrs = trsByEnvId.get(reportEnvironment.id) ?? [];
198
210
  const envConvertedTrs = envTrs
199
211
  .map((tr) => convertedTrsById.get(tr.id))
200
212
  .filter((tr) => Boolean(tr));
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/plugin-awesome",
3
- "version": "3.20.0",
3
+ "version": "3.20.1",
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.20.0",
34
- "@allurereport/core-api": "3.20.0",
35
- "@allurereport/plugin-api": "3.20.0",
36
- "@allurereport/web-commons": "3.20.0",
33
+ "@allurereport/charts-api": "3.20.1",
34
+ "@allurereport/core-api": "3.20.1",
35
+ "@allurereport/plugin-api": "3.20.1",
36
+ "@allurereport/web-commons": "3.20.1",
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.20.0",
42
+ "@allurereport/web-awesome": "3.20.1",
43
43
  "@types/d3-shape": "^3.1.8",
44
44
  "@types/markdown-it": "^14.1.2",
45
45
  "@types/node": "^20",