@allurereport/core 3.20.1 → 3.21.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.
package/dist/config.d.ts CHANGED
@@ -7,6 +7,7 @@ export interface ConfigOverride {
7
7
  output?: Config["output"];
8
8
  open?: Config["open"];
9
9
  port?: Config["port"];
10
+ host?: Config["host"];
10
11
  hideLabels?: Config["hideLabels"];
11
12
  historyPath?: Config["historyPath"];
12
13
  historyBaseUrl?: Config["historyBaseUrl"];
package/dist/config.js CHANGED
@@ -87,6 +87,7 @@ export const validateConfig = (config) => {
87
87
  "output",
88
88
  "open",
89
89
  "port",
90
+ "host",
90
91
  "hideLabels",
91
92
  "historyPath",
92
93
  "historyBaseUrl",
@@ -208,6 +209,7 @@ export const resolveConfig = async (config, override = {}) => {
208
209
  const name = override.name ?? config.name ?? "Allure Report";
209
210
  const open = override.open ?? config.open ?? false;
210
211
  const port = override.port ?? config.port ?? undefined;
212
+ const host = override.host ?? config.host ?? undefined;
211
213
  const hideLabels = override.hideLabels ?? config.hideLabels;
212
214
  const historyPath = override.historyPath ?? config.historyPath;
213
215
  const historyBaseUrl = override.historyBaseUrl ?? config.historyBaseUrl;
@@ -252,6 +254,7 @@ export const resolveConfig = async (config, override = {}) => {
252
254
  output,
253
255
  open,
254
256
  port,
257
+ host,
255
258
  hideLabels,
256
259
  resolutions,
257
260
  environment,
package/dist/history.js CHANGED
@@ -9,7 +9,7 @@ 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 _AllureLocalHistory_cachedHistory, _AllureLocalHistory_openFileToReadIfExists, _AllureLocalHistory_ensureFileOpenedToAppend, _AllureLocalHistory_findFirstEntryAddress, _AllureLocalHistory_throwUnexpectedReadError;
12
+ var _AllureLocalHistory_cachedHistory, _AllureLocalHistory_closeStreams, _AllureLocalHistory_openFileToReadIfExists, _AllureLocalHistory_ensureFileOpenedToAppend, _AllureLocalHistory_findFirstEntryAddress, _AllureLocalHistory_throwUnexpectedReadError;
13
13
  import { once } from "node:events";
14
14
  import { mkdir, open } from "node:fs/promises";
15
15
  import path from "node:path";
@@ -20,13 +20,14 @@ import { isFileNotFoundError } from "./utils/misc.js";
20
20
  const createHistoryItems = (testResults, remoteUrl) => {
21
21
  return testResults
22
22
  .filter((tr) => tr.retryHash)
23
- .map(({ id, name, fullName, environment, retryHash, status, error: { message, trace } = {}, start, stop, duration, labels, }) => {
23
+ .map(({ id, name, fullName, environment, retryHash, status, retries = [], error: { message, trace } = {}, start, stop, duration, labels, }) => {
24
24
  return {
25
25
  id,
26
26
  name,
27
27
  fullName,
28
28
  environment,
29
29
  status,
30
+ retries: retries.map((retry) => retry.status).reverse(),
30
31
  message,
31
32
  trace,
32
33
  start,
@@ -82,10 +83,35 @@ export const createHistory = (reportUuid, reportName = "Allure Report", testCase
82
83
  url: remoteUrl,
83
84
  };
84
85
  };
86
+ const closeStream = async (stream) => {
87
+ if (stream.closed) {
88
+ return;
89
+ }
90
+ await new Promise((resolve) => {
91
+ stream.once("error", () => { });
92
+ stream.once("close", () => resolve());
93
+ stream.destroy();
94
+ });
95
+ };
96
+ const closeFileHandle = async (file) => {
97
+ try {
98
+ await file.close();
99
+ }
100
+ catch (err) {
101
+ if (err?.code !== "EBADF") {
102
+ throw err;
103
+ }
104
+ }
105
+ };
85
106
  export class AllureLocalHistory {
86
107
  constructor(params) {
87
108
  this.params = params;
88
109
  _AllureLocalHistory_cachedHistory.set(this, []);
110
+ _AllureLocalHistory_closeStreams.set(this, async (streams) => {
111
+ for (const stream of streams) {
112
+ await closeStream(stream);
113
+ }
114
+ });
89
115
  _AllureLocalHistory_openFileToReadIfExists.set(this, async (filePath) => {
90
116
  try {
91
117
  return await open(filePath, "r");
@@ -175,9 +201,11 @@ export class AllureLocalHistory {
175
201
  if (historyFile === undefined) {
176
202
  return [];
177
203
  }
204
+ const openedStreams = [];
178
205
  try {
179
206
  const start = await __classPrivateFieldGet(this, _AllureLocalHistory_findFirstEntryAddress, "f").call(this, historyFile, this.params.limit);
180
207
  const stream = historyFile.createReadStream({ start, encoding: "utf-8", autoClose: false });
208
+ openedStreams.push(stream);
181
209
  const historyPoints = [];
182
210
  const readlineInterface = readline
183
211
  .createInterface({ input: stream, terminal: false, crlfDelay: Infinity })
@@ -192,7 +220,8 @@ export class AllureLocalHistory {
192
220
  return __classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f");
193
221
  }
194
222
  finally {
195
- await historyFile.close();
223
+ await __classPrivateFieldGet(this, _AllureLocalHistory_closeStreams, "f").call(this, openedStreams);
224
+ await closeFileHandle(historyFile);
196
225
  }
197
226
  }
198
227
  async appendHistory(data) {
@@ -202,6 +231,7 @@ export class AllureLocalHistory {
202
231
  const { limit } = this.params;
203
232
  await mkdir(parentDir, { recursive: true });
204
233
  const { file: historyFile, exists: historyExists } = await __classPrivateFieldGet(this, _AllureLocalHistory_ensureFileOpenedToAppend, "f").call(this, fullPath);
234
+ const openedStreams = [];
205
235
  let dst;
206
236
  try {
207
237
  if (limit === 0) {
@@ -210,9 +240,11 @@ export class AllureLocalHistory {
210
240
  return;
211
241
  }
212
242
  dst = historyFile.createWriteStream({ encoding: "utf-8", start: 0, autoClose: false });
243
+ openedStreams.push(dst);
213
244
  if (historyExists) {
214
245
  const start = await __classPrivateFieldGet(this, _AllureLocalHistory_findFirstEntryAddress, "f").call(this, historyFile, limit ? limit - 1 : undefined);
215
246
  const src = historyFile.createReadStream({ start, autoClose: false });
247
+ openedStreams.push(src);
216
248
  await pipeline(src, dst, { end: false });
217
249
  }
218
250
  const sources = [JSON.stringify(normalizedData), Buffer.from([0x0a])];
@@ -222,11 +254,8 @@ export class AllureLocalHistory {
222
254
  }
223
255
  }
224
256
  finally {
225
- const closing = historyFile.close();
226
- if (historyFile.fd !== -1) {
227
- dst?.destroy();
228
- }
229
- await closing;
257
+ await __classPrivateFieldGet(this, _AllureLocalHistory_closeStreams, "f").call(this, openedStreams);
258
+ await closeFileHandle(historyFile);
230
259
  if (limit !== 0) {
231
260
  __classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f").push(normalizedData);
232
261
  }
@@ -236,4 +265,4 @@ export class AllureLocalHistory {
236
265
  }
237
266
  }
238
267
  }
239
- _AllureLocalHistory_cachedHistory = new WeakMap(), _AllureLocalHistory_openFileToReadIfExists = new WeakMap(), _AllureLocalHistory_ensureFileOpenedToAppend = new WeakMap(), _AllureLocalHistory_findFirstEntryAddress = new WeakMap(), _AllureLocalHistory_throwUnexpectedReadError = new WeakMap();
268
+ _AllureLocalHistory_cachedHistory = new WeakMap(), _AllureLocalHistory_closeStreams = new WeakMap(), _AllureLocalHistory_openFileToReadIfExists = new WeakMap(), _AllureLocalHistory_ensureFileOpenedToAppend = new WeakMap(), _AllureLocalHistory_findFirstEntryAddress = new WeakMap(), _AllureLocalHistory_throwUnexpectedReadError = new WeakMap();
package/dist/report.js CHANGED
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _AllureReport_instances, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_realtimeChannel, _AllureReport_realtimeUpdateScheduler, _AllureReport_realTime, _AllureReport_hideLabels, _AllureReport_output, _AllureReport_history, _AllureReport_historyBaseUrl, _AllureReport_appendHistory, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_environments, _AllureReport_globalAttachments, _AllureReport_knownIssuesPath, _AllureReport_dumpTempDirs, _AllureReport_cwd, _AllureReport_state, _AllureReport_executionStage, _AllureReport_historyDataPoint, _AllureReport_summaryPath, _AllureReport_testResultsRegistryPath, _AllureReport_summariesByPluginId, _AllureReport_publishedRemoteHrefs, _AllureReport_artifactFilesByPath, _AllureReport_published, _AllureReport_endGeneratePerfSpan, _AllureReport_resolvedReportUrl, _AllureReport_reportUrl, _AllureReport_resolveReportUrl, _AllureReport_createHistoryDataPoint, _AllureReport_ingestSelfPerfMetrics, _AllureReport_prepareReportFiles, _AllureReport_publish, _AllureReport_getCwd, _AllureReport_runRealtimeUpdate, _AllureReport_recordArtifact, _AllureReport_restoreStateDumps, _AllureReport_getReportsToPublish, _AllureReport_cleanupFailedRemoteReport, _AllureReport_logPublishError, _AllureReport_applyPublishLinksToSummaries, _AllureReport_cloneSummariesByPluginId, _AllureReport_writeSummaryFiles, _AllureReport_writeTestResultRegistry, _AllureReport_getRootRemoteReportFiles, _AllureReport_writeQualityGateFiles, _AllureReport_finishArtifactsManifest, _AllureReport_generateRootSummary, _AllureReport_finishGeneratePerfSpan, _AllureReport_finishPerfMetrics, _AllureReport_eachPlugin, _AllureReport_getPluginState;
12
+ var _AllureReport_instances, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_realtimeChannel, _AllureReport_realtimeUpdateScheduler, _AllureReport_realTime, _AllureReport_hideLabels, _AllureReport_output, _AllureReport_history, _AllureReport_historyBaseUrl, _AllureReport_appendHistory, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_environments, _AllureReport_globalAttachments, _AllureReport_knownIssuesPath, _AllureReport_dumpTempDirs, _AllureReport_cwd, _AllureReport_state, _AllureReport_executionStage, _AllureReport_historyDataPoint, _AllureReport_summaryPath, _AllureReport_overviewHref, _AllureReport_testResultsRegistryPath, _AllureReport_summariesByPluginId, _AllureReport_publishedRemoteHrefs, _AllureReport_artifactFilesByPath, _AllureReport_published, _AllureReport_endGeneratePerfSpan, _AllureReport_resolvedReportUrl, _AllureReport_reportUrl, _AllureReport_resolveReportUrl, _AllureReport_createHistoryDataPoint, _AllureReport_ingestSelfPerfMetrics, _AllureReport_prepareReportFiles, _AllureReport_publish, _AllureReport_getCwd, _AllureReport_runRealtimeUpdate, _AllureReport_recordArtifact, _AllureReport_restoreStateDumps, _AllureReport_resolveOverviewHref, _AllureReport_getReportsToPublish, _AllureReport_cleanupFailedRemoteReport, _AllureReport_logPublishError, _AllureReport_applyPublishLinksToSummaries, _AllureReport_cloneSummariesByPluginId, _AllureReport_writeSummaryFiles, _AllureReport_writeTestResultRegistry, _AllureReport_getRootRemoteReportFiles, _AllureReport_writeQualityGateFiles, _AllureReport_finishArtifactsManifest, _AllureReport_generateRootSummary, _AllureReport_finishGeneratePerfSpan, _AllureReport_finishPerfMetrics, _AllureReport_eachPlugin, _AllureReport_getPluginState;
13
13
  import console from "node:console";
14
14
  import { randomUUID } from "node:crypto";
15
15
  import { once } from "node:events";
@@ -48,6 +48,7 @@ const MAX_READ_CONCURRENCY = 256;
48
48
  const DEFAULT_UPLOAD_CONCURRENCY = 10;
49
49
  const TEST_RESULTS_REGISTRY_FILENAME = "test-results.json";
50
50
  const QUALITY_GATE_RESULTS_FILENAME = "quality-gate.json";
51
+ const AUXILIARY_OUTPUT_DIRECTORIES = new Set(["export"]);
51
52
  const ROOT_INTEGRATION_FILENAMES = new Set([
52
53
  TEST_RESULTS_REGISTRY_FILENAME,
53
54
  QUALITY_GATE_RESULTS_FILENAME,
@@ -66,11 +67,15 @@ const readConcurrency = () => {
66
67
  return Math.min(MAX_READ_CONCURRENCY, Math.max(1, parsed));
67
68
  };
68
69
  const clonePluginSummary = (summary) => structuredClone(summary);
69
- const remoteReportParams = (ci) => {
70
+ const remoteBranchParams = (ci, branch) => {
70
71
  const repo = ci?.repoName;
71
- const branch = ci?.jobRunBranch;
72
72
  return repo && branch ? { repo, branch } : {};
73
73
  };
74
+ const remoteHistoryParams = (ci) => {
75
+ const historyBranch = ci?.targetBranch || ci?.jobRunBranch;
76
+ return remoteBranchParams(ci, historyBranch);
77
+ };
78
+ const remoteReportParams = (ci) => remoteBranchParams(ci, ci?.jobRunBranch);
74
79
  const errorDetails = (err) => (err instanceof Error ? (err.stack ?? err.message) : String(err));
75
80
  const getExecutorReportUrl = (executor) => {
76
81
  if (!executor || typeof executor !== "object" || !("reportUrl" in executor)) {
@@ -126,6 +131,7 @@ export class AllureReport {
126
131
  _AllureReport_executionStage.set(this, "init");
127
132
  _AllureReport_historyDataPoint.set(this, void 0);
128
133
  _AllureReport_summaryPath.set(this, void 0);
134
+ _AllureReport_overviewHref.set(this, void 0);
129
135
  _AllureReport_testResultsRegistryPath.set(this, void 0);
130
136
  _AllureReport_summariesByPluginId.set(this, new Map());
131
137
  _AllureReport_publishedRemoteHrefs.set(this, new Set());
@@ -149,7 +155,10 @@ export class AllureReport {
149
155
  __classPrivateFieldSet(this, _AllureReport_resolvedReportUrl, executorReportUrl, "f");
150
156
  });
151
157
  _AllureReport_createHistoryDataPoint.set(this, async (flattenReport) => {
152
- const allTrs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
158
+ const allTrs = await Promise.all((await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults()).map(async (tr) => ({
159
+ ...tr,
160
+ retries: await __classPrivateFieldGet(this, _AllureReport_store, "f").retriesByTrId(tr.id),
161
+ })));
153
162
  const allTcs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
154
163
  const historyUrl = __classPrivateFieldGet(this, _AllureReport_reportUrl, "f") ?? (!flattenReport && __classPrivateFieldGet(this, _AllureReport_historyBaseUrl, "f") ? __classPrivateFieldGet(this, _AllureReport_historyBaseUrl, "f") : __classPrivateFieldGet(this, _AllureReport_resolvedReportUrl, "f"));
155
164
  return createHistory(this.reportUuid, this.reportName, allTcs, allTrs, historyUrl ?? "", await __classPrivateFieldGet(this, _AllureReport_store, "f").allMetrics());
@@ -747,6 +756,19 @@ export class AllureReport {
747
756
  }
748
757
  return restoredCount;
749
758
  }));
759
+ _AllureReport_resolveOverviewHref.set(this, async () => {
760
+ if (__classPrivateFieldGet(this, _AllureReport_realTime, "f")) {
761
+ return undefined;
762
+ }
763
+ let summariesCount = 0;
764
+ await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
765
+ const summary = await plugin.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
766
+ if (summary) {
767
+ summariesCount += 1;
768
+ }
769
+ });
770
+ return summariesCount > 1 ? "../index.html" : undefined;
771
+ });
750
772
  _AllureReport_getReportsToPublish.set(this, async () => {
751
773
  const reports = [];
752
774
  for (const { enabled, id, options } of __classPrivateFieldGet(this, _AllureReport_plugins, "f")) {
@@ -866,6 +888,7 @@ export class AllureReport {
866
888
  return;
867
889
  }
868
890
  await __classPrivateFieldGet(this, _AllureReport_resolveReportUrl, "f").call(this);
891
+ __classPrivateFieldSet(this, _AllureReport_overviewHref, await __classPrivateFieldGet(this, _AllureReport_resolveOverviewHref, "f").call(this), "f");
869
892
  await measurePerf(PERF_METRIC_NAMES.generatePluginsDone, async () => {
870
893
  await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
871
894
  await measurePerf(`${PERF_METRIC_PREFIXES.generatePluginDone}${context.id}`, async () => {
@@ -899,7 +922,8 @@ export class AllureReport {
899
922
  catch { }
900
923
  const outputEntries = await Promise.all(outputDirFiles.map(async (file) => ({ file, stats: await lstat(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), file)) })));
901
924
  const outputDirectoryEntries = outputEntries.filter(({ stats }) => stats.isDirectory());
902
- const shouldFlattenOutput = outputDirectoryEntries.length === 1;
925
+ const reportDirectoryEntries = outputDirectoryEntries.filter(({ file }) => !AUXILIARY_OUTPUT_DIRECTORIES.has(file));
926
+ const shouldFlattenOutput = reportDirectoryEntries.length === 1 && __classPrivateFieldGet(this, _AllureReport_plugins, "f").some(({ id }) => id === reportDirectoryEntries[0].file);
903
927
  __classPrivateFieldSet(this, _AllureReport_historyDataPoint, await __classPrivateFieldGet(this, _AllureReport_createHistoryDataPoint, "f").call(this, shouldFlattenOutput), "f");
904
928
  await __classPrivateFieldGet(this, _AllureReport_publish, "f").call(this);
905
929
  if (__classPrivateFieldGet(this, _AllureReport_knownIssuesPath, "f")) {
@@ -909,7 +933,7 @@ export class AllureReport {
909
933
  return;
910
934
  }
911
935
  if (shouldFlattenOutput) {
912
- const reportPath = join(__classPrivateFieldGet(this, _AllureReport_output, "f"), outputDirectoryEntries[0].file);
936
+ const reportPath = join(__classPrivateFieldGet(this, _AllureReport_output, "f"), reportDirectoryEntries[0].file);
913
937
  const reportContent = await readdir(reportPath);
914
938
  for (const entry of reportContent) {
915
939
  if (ROOT_INTEGRATION_FILENAMES.has(entry)) {
@@ -1015,6 +1039,7 @@ export class AllureReport {
1015
1039
  }
1016
1040
  : {}),
1017
1041
  reportUrl: this.reportUrl,
1042
+ overviewHref: __classPrivateFieldGet(this, _AllureReport_overviewHref, "f"),
1018
1043
  realTime: !!__classPrivateFieldGet(this, _AllureReport_realTime, "f"),
1019
1044
  output: __classPrivateFieldGet(this, _AllureReport_output, "f"),
1020
1045
  ci: __classPrivateFieldGet(this, _AllureReport_ci, "f"),
@@ -1075,7 +1100,7 @@ export class AllureReport {
1075
1100
  if (__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")) {
1076
1101
  __classPrivateFieldSet(this, _AllureReport_history, new AllureRemoteHistory({
1077
1102
  limit: historyLimit,
1078
- ...remoteReportParams(__classPrivateFieldGet(this, _AllureReport_ci, "f")),
1103
+ ...remoteHistoryParams(__classPrivateFieldGet(this, _AllureReport_ci, "f")),
1079
1104
  allureServiceClient: __classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f"),
1080
1105
  }), "f");
1081
1106
  }
@@ -1122,6 +1147,6 @@ export class AllureReport {
1122
1147
  __classPrivateFieldSet(this, _AllureReport_reportUrl, url, "f");
1123
1148
  }
1124
1149
  }
1125
- _AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_realtimeChannel = new WeakMap(), _AllureReport_realtimeUpdateScheduler = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_hideLabels = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_historyBaseUrl = new WeakMap(), _AllureReport_appendHistory = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_environments = new WeakMap(), _AllureReport_globalAttachments = new WeakMap(), _AllureReport_knownIssuesPath = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_cwd = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_historyDataPoint = new WeakMap(), _AllureReport_summaryPath = new WeakMap(), _AllureReport_testResultsRegistryPath = new WeakMap(), _AllureReport_summariesByPluginId = new WeakMap(), _AllureReport_publishedRemoteHrefs = new WeakMap(), _AllureReport_artifactFilesByPath = new WeakMap(), _AllureReport_published = new WeakMap(), _AllureReport_endGeneratePerfSpan = new WeakMap(), _AllureReport_resolvedReportUrl = new WeakMap(), _AllureReport_reportUrl = new WeakMap(), _AllureReport_resolveReportUrl = new WeakMap(), _AllureReport_createHistoryDataPoint = new WeakMap(), _AllureReport_ingestSelfPerfMetrics = new WeakMap(), _AllureReport_prepareReportFiles = new WeakMap(), _AllureReport_publish = new WeakMap(), _AllureReport_getCwd = new WeakMap(), _AllureReport_runRealtimeUpdate = new WeakMap(), _AllureReport_recordArtifact = new WeakMap(), _AllureReport_restoreStateDumps = new WeakMap(), _AllureReport_getReportsToPublish = new WeakMap(), _AllureReport_cleanupFailedRemoteReport = new WeakMap(), _AllureReport_logPublishError = new WeakMap(), _AllureReport_applyPublishLinksToSummaries = new WeakMap(), _AllureReport_cloneSummariesByPluginId = new WeakMap(), _AllureReport_writeSummaryFiles = new WeakMap(), _AllureReport_writeTestResultRegistry = new WeakMap(), _AllureReport_getRootRemoteReportFiles = new WeakMap(), _AllureReport_writeQualityGateFiles = new WeakMap(), _AllureReport_finishArtifactsManifest = new WeakMap(), _AllureReport_generateRootSummary = new WeakMap(), _AllureReport_finishGeneratePerfSpan = new WeakMap(), _AllureReport_finishPerfMetrics = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
1150
+ _AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_realtimeChannel = new WeakMap(), _AllureReport_realtimeUpdateScheduler = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_hideLabels = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_historyBaseUrl = new WeakMap(), _AllureReport_appendHistory = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_environments = new WeakMap(), _AllureReport_globalAttachments = new WeakMap(), _AllureReport_knownIssuesPath = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_cwd = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_historyDataPoint = new WeakMap(), _AllureReport_summaryPath = new WeakMap(), _AllureReport_overviewHref = new WeakMap(), _AllureReport_testResultsRegistryPath = new WeakMap(), _AllureReport_summariesByPluginId = new WeakMap(), _AllureReport_publishedRemoteHrefs = new WeakMap(), _AllureReport_artifactFilesByPath = new WeakMap(), _AllureReport_published = new WeakMap(), _AllureReport_endGeneratePerfSpan = new WeakMap(), _AllureReport_resolvedReportUrl = new WeakMap(), _AllureReport_reportUrl = new WeakMap(), _AllureReport_resolveReportUrl = new WeakMap(), _AllureReport_createHistoryDataPoint = new WeakMap(), _AllureReport_ingestSelfPerfMetrics = new WeakMap(), _AllureReport_prepareReportFiles = new WeakMap(), _AllureReport_publish = new WeakMap(), _AllureReport_getCwd = new WeakMap(), _AllureReport_runRealtimeUpdate = new WeakMap(), _AllureReport_recordArtifact = new WeakMap(), _AllureReport_restoreStateDumps = new WeakMap(), _AllureReport_resolveOverviewHref = new WeakMap(), _AllureReport_getReportsToPublish = new WeakMap(), _AllureReport_cleanupFailedRemoteReport = new WeakMap(), _AllureReport_logPublishError = new WeakMap(), _AllureReport_applyPublishLinksToSummaries = new WeakMap(), _AllureReport_cloneSummariesByPluginId = new WeakMap(), _AllureReport_writeSummaryFiles = new WeakMap(), _AllureReport_writeTestResultRegistry = new WeakMap(), _AllureReport_getRootRemoteReportFiles = new WeakMap(), _AllureReport_writeQualityGateFiles = new WeakMap(), _AllureReport_finishArtifactsManifest = new WeakMap(), _AllureReport_generateRootSummary = new WeakMap(), _AllureReport_finishGeneratePerfSpan = new WeakMap(), _AllureReport_finishPerfMetrics = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
1126
1151
  return init ? new DefaultPluginState({}) : __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id];
1127
1152
  };
@@ -36,7 +36,8 @@ export const testFixtureResultRawToState = (stateData, raw, context) => {
36
36
  };
37
37
  };
38
38
  export const testResultRawToState = (stateData, raw, context) => {
39
- const legacyTestCaseHash = calculateLegacyTestCaseHash(raw);
39
+ const testCaseHash = calculateTestCaseHash(raw.testId, raw.fullName);
40
+ const legacyTestCaseHash = calculateLegacyTestCaseHash(raw, testCaseHash);
40
41
  const allureId = raw.labels
41
42
  ?.find((label) => (label?.name === "ALLURE_ID" || label?.name === "AS_ID") && label.value?.trim())
42
43
  ?.value?.trim();
@@ -45,9 +46,8 @@ export const testResultRawToState = (stateData, raw, context) => {
45
46
  const threadId = findByLabelName(labels, "thread");
46
47
  const name = raw.name || "Unknown test";
47
48
  const parameters = convertParameters(raw.parameters);
48
- const error = convertRawError(raw);
49
49
  const errors = convertTestErrors(raw);
50
- const testCaseHash = calculateTestCaseHash(raw.testId, raw.fullName);
50
+ const error = errors?.[0] ?? convertRawError(raw);
51
51
  const parametersHash = calculateParametersHash(parameters);
52
52
  const testCase = processTestCase({ stateData, raw, allureId, testCaseHash });
53
53
  return {
@@ -60,7 +60,7 @@ export const testResultRawToState = (stateData, raw, context) => {
60
60
  environmentHash: null,
61
61
  retryHash: calculateRetryHash({ testCaseHash, parametersHash }),
62
62
  status: raw.status ?? defaultStatus,
63
- error: errors?.[0] ?? error,
63
+ error,
64
64
  errors,
65
65
  ...processTimings(raw),
66
66
  description: raw.description,
@@ -89,18 +89,12 @@ export const testResultRawToState = (stateData, raw, context) => {
89
89
  titlePath: raw.titlePath ?? [],
90
90
  };
91
91
  };
92
- const calculateLegacyTestCaseHash = (raw) => {
92
+ const calculateLegacyTestCaseHash = (raw, testCaseHash) => {
93
93
  const maybeAllureId = raw.labels?.find((label) => (label?.name === "ALLURE_ID" || label?.name === "AS_ID") && label.value !== "-1")?.value;
94
94
  if (maybeAllureId) {
95
95
  return md5(`ALLURE_ID=${maybeAllureId}`);
96
96
  }
97
- if (raw.testId) {
98
- return md5(raw.testId);
99
- }
100
- if (raw.fullName) {
101
- return md5(raw.fullName);
102
- }
103
- return undefined;
97
+ return testCaseHash ?? undefined;
104
98
  };
105
99
  const processTestCase = ({ stateData: { testCases }, raw, allureId, testCaseHash, }) => {
106
100
  if (testCaseHash) {
@@ -201,7 +195,16 @@ const processTimings = ({ start, stop, duration, }) => {
201
195
  return { start: undefined, stop: undefined, duration };
202
196
  };
203
197
  const convertLabels = (labels) => {
204
- return labels?.filter(notNull)?.map(convertLabel)?.flatMap(processTagLabels).map(normalizeAllureIdLabel) ?? [];
198
+ const convertedLabels = [];
199
+ for (const label of labels ?? []) {
200
+ if (!notNull(label)) {
201
+ continue;
202
+ }
203
+ for (const expandedLabel of processTagLabels(convertLabel(label))) {
204
+ convertedLabels.push(normalizeAllureIdLabel(expandedLabel));
205
+ }
206
+ }
207
+ return convertedLabels;
205
208
  };
206
209
  const convertLabel = (label) => {
207
210
  return {
@@ -210,16 +213,19 @@ const convertLabel = (label) => {
210
213
  };
211
214
  };
212
215
  const convertSteps = (stateData, steps) => {
213
- const convertedStepData = steps?.filter(notNull)?.map((step) => convertStep(stateData, step)) ?? [];
214
- return {
215
- convertedSteps: convertedStepData.map(({ convertedStep }) => convertedStep),
216
- messages: new Set(convertedStepData.reduce((acc, { messages }) => {
217
- if (messages) {
218
- acc.push(...messages);
219
- }
220
- return acc;
221
- }, [])),
222
- };
216
+ const convertedSteps = [];
217
+ const messages = new Set();
218
+ for (const step of steps ?? []) {
219
+ if (!notNull(step)) {
220
+ continue;
221
+ }
222
+ const converted = convertStep(stateData, step);
223
+ convertedSteps.push(converted.convertedStep);
224
+ for (const message of converted.messages ?? []) {
225
+ messages.add(message);
226
+ }
227
+ }
228
+ return { convertedSteps, messages };
223
229
  };
224
230
  const convertStep = (stateData, step) => {
225
231
  if (step.type === "step") {
@@ -251,10 +257,15 @@ const convertStep = (stateData, step) => {
251
257
  },
252
258
  };
253
259
  };
254
- const convertParameters = (parameters) => parameters
255
- ?.filter(notNull)
256
- ?.filter((p) => typeof p.name === "string" && p.name.length > 0)
257
- ?.map(convertParameter) ?? [];
260
+ const convertParameters = (parameters) => {
261
+ const convertedParameters = [];
262
+ for (const parameter of parameters ?? []) {
263
+ if (notNull(parameter) && typeof parameter.name === "string" && parameter.name.length > 0) {
264
+ convertedParameters.push(convertParameter(parameter));
265
+ }
266
+ }
267
+ return convertedParameters;
268
+ };
258
269
  const convertParameter = (param) => ({
259
270
  name: param.name ?? UNKNOWN_PARAMETER_VALUE,
260
271
  value: param.value ?? UNKNOWN_PARAMETER_VALUE,
@@ -262,10 +273,15 @@ const convertParameter = (param) => ({
262
273
  excluded: param.excluded ?? false,
263
274
  masked: param.masked ?? false,
264
275
  });
265
- const convertLinks = (links) => links
266
- ?.filter(notNull)
267
- ?.filter((l) => l.url)
268
- ?.map(convertLink) ?? [];
276
+ const convertLinks = (links) => {
277
+ const convertedLinks = [];
278
+ for (const link of links ?? []) {
279
+ if (notNull(link) && link.url) {
280
+ convertedLinks.push(convertLink(link));
281
+ }
282
+ }
283
+ return convertedLinks;
284
+ };
269
285
  const convertLink = (link) => ({
270
286
  name: link.name,
271
287
  url: link.url ?? UNKNOWN_PARAMETER_VALUE,
@@ -41,7 +41,13 @@ export class RetrySubstore {
41
41
  __classPrivateFieldGet(this, _RetrySubstore_testResultsByRetryHash, "f").set(testResult.retryHash, [testResult]);
42
42
  return;
43
43
  }
44
- results.push(testResult);
44
+ const existingIndex = results.findIndex((attempt) => attempt.id === testResult.id);
45
+ if (existingIndex !== -1) {
46
+ results.splice(existingIndex, 1, testResult);
47
+ }
48
+ else {
49
+ results.push(testResult);
50
+ }
45
51
  results.sort((first, second) => __classPrivateFieldGet(this, _RetrySubstore_instances, "m", _RetrySubstore_compareResults).call(this, first, second));
46
52
  results.forEach((attempt, index) => {
47
53
  attempt.isRetry = index !== 0;
@@ -11,7 +11,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
11
11
  };
12
12
  var _DefaultAllureStore_instances, _DefaultAllureStore_testResults, _DefaultAllureStore_attachments, _DefaultAllureStore_attachmentContents, _DefaultAllureStore_testCases, _DefaultAllureStore_metadata, _DefaultAllureStore_history, _DefaultAllureStore_detectFlaky, _DefaultAllureStore_resolutionsConfig, _DefaultAllureStore_resolutionIssues, _DefaultAllureStore_testResultIdsByResolutionIssueId, _DefaultAllureStore_resolutionIssueIdByTestResultId, _DefaultAllureStore_fixtures, _DefaultAllureStore_defaultLabels, _DefaultAllureStore_environment, _DefaultAllureStore_environmentsConfig, _DefaultAllureStore_reportVariables, _DefaultAllureStore_realtimeDispatcher, _DefaultAllureStore_realtimeSubscriber, _DefaultAllureStore_allowedEnvironmentIds, _DefaultAllureStore_retrySubstore, _DefaultAllureStore_testResultIdsByEnvironmentId, _DefaultAllureStore_globalAttachmentIds, _DefaultAllureStore_globalAttachmentIdsByEnv, _DefaultAllureStore_globalErrors, _DefaultAllureStore_globalErrorsByEnv, _DefaultAllureStore_processGlobalAttachmentIds, _DefaultAllureStore_processGlobalAttachmentIdsByEnv, _DefaultAllureStore_processGlobalErrors, _DefaultAllureStore_processGlobalErrorsByEnv, _DefaultAllureStore_globalExitCode, _DefaultAllureStore_checkResultsById, _DefaultAllureStore_qualityGateResults, _DefaultAllureStore_metrics, _DefaultAllureStore_performance, _DefaultAllureStore_historyPoints, _DefaultAllureStore_historyLookup, _DefaultAllureStore_environments, _DefaultAllureStore_mergeEnvironmentIdentity, _DefaultAllureStore_environmentIdForLookup, _DefaultAllureStore_environmentIdByName, _DefaultAllureStore_addEnvironments, _DefaultAllureStore_setTestResultEnvironmentId, _DefaultAllureStore_assertAllowedEnvironmentId, _DefaultAllureStore_assertAllowedStoredEnvironment, _DefaultAllureStore_environmentIdByTestResult, _DefaultAllureStore_assignIdentityHashes, _DefaultAllureStore_classifyResolution, _DefaultAllureStore_associateResolutionIssue, _DefaultAllureStore_removeResolutionIssueAssociation, _DefaultAllureStore_rebuildRetrySubstore, _DefaultAllureStore_rebuildIdentityIndexes, _DefaultAllureStore_rebuildEnvironmentIndexes, _DefaultAllureStore_resolveGlobalEnvironmentIdentity, _DefaultAllureStore_globalAttachmentId, _DefaultAllureStore_processGlobalAttachmentId, _DefaultAllureStore_indexGlobalError, _DefaultAllureStore_addGlobalError, _DefaultAllureStore_indexGlobalAttachment, _DefaultAllureStore_addGlobalAttachment, _DefaultAllureStore_resetProcessGlobals, _DefaultAllureStore_getHistoryLookup, _DefaultAllureStore_historyFor, _DefaultAllureStore_applyHistoryFlags, _DefaultAllureStore_restoreAttachmentContent, _DefaultAllureStore_relinkRestoredAttachmentSteps, _DefaultAllureStore_retriesByTr, _DefaultAllureStore_historyByTr;
13
13
  import { extname } from "node:path";
14
- import { DEFAULT_ENVIRONMENT, DEFAULT_ENVIRONMENT_IDENTITY, calculateEnvironmentHash, calculateParametersHash, calculateRetryHash, calculateTestCaseHash, compareBy, createDictionary, fallbackTestCaseIdLabelName, getWorstStatus, createHistoryTestResultLookup, normalizeHistoryDataPoint, ordinal, reverse, resolveMetricSamples, validateEnvironmentId, validateEnvironmentName, } from "@allurereport/core-api";
14
+ import { DEFAULT_ENVIRONMENT, DEFAULT_ENVIRONMENT_IDENTITY, calculateEnvironmentHash, calculateParametersHash, calculateRetryHash, calculateTestCaseHash, compareBy, createDictionary, fallbackTestCaseIdLabelName, getWorstStatus, createHistoryTestResultLookup, hasRetriesStatusChange, normalizeHistoryDataPoint, ordinal, reverse, resolveMetricSamples, validateEnvironmentId, validateEnvironmentName, } from "@allurereport/core-api";
15
15
  import { md5, } from "@allurereport/plugin-api";
16
16
  import { createResolutionIssue, getResolutionByRules, isIgnoredFailure } from "../resolutions.js";
17
17
  import { environmentIdentityById, normalizeEnvironmentDescriptorMap, resolveEnvironmentIdentity, resolveStoredEnvironmentIdentity, validateAllowedEnvironmentId, } from "../utils/environment.js";
@@ -22,10 +22,11 @@ import { testFixtureResultRawToState, testResultRawToState } from "./convert.js"
22
22
  import { RetrySubstore } from "./retrySubstore.js";
23
23
  const index = (indexMap, key, ...items) => {
24
24
  if (key) {
25
- if (!indexMap.has(key)) {
26
- indexMap.set(key, []);
25
+ let current = indexMap.get(key);
26
+ if (!current) {
27
+ current = [];
28
+ indexMap.set(key, current);
27
29
  }
28
- const current = indexMap.get(key);
29
30
  current.push(...items);
30
31
  }
31
32
  };
@@ -776,6 +777,9 @@ export class DefaultAllureStore {
776
777
  if (retries.length > 0) {
777
778
  statistic.retries = (statistic.retries ?? 0) + 1;
778
779
  }
780
+ if (hasRetriesStatusChange(tr, retries)) {
781
+ statistic.retriesStatusChange = (statistic.retriesStatusChange ?? 0) + 1;
782
+ }
779
783
  if (tr.flaky) {
780
784
  statistic.flaky = (statistic.flaky ?? 0) + 1;
781
785
  }
@@ -1,2 +1,2 @@
1
+ export { md5 } from "@allurereport/plugin-api";
1
2
  export declare const shortHash: () => string;
2
- export declare const md5: (data: string) => string;
@@ -1,3 +1,3 @@
1
- import { randomBytes, createHash } from "node:crypto";
1
+ import { randomBytes } from "node:crypto";
2
+ export { md5 } from "@allurereport/plugin-api";
2
3
  export const shortHash = () => randomBytes(8).toString("hex");
3
- export const md5 = (data) => createHash("md5").update(data).digest("hex");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/core",
3
- "version": "3.20.1",
3
+ "version": "3.21.0",
4
4
  "description": "Collection of generic Allure utilities used across the entire project",
5
5
  "keywords": [
6
6
  "allure"
@@ -21,32 +21,35 @@
21
21
  "build": "run clean && tsc --project ./tsconfig.json",
22
22
  "clean": "rimraf ./dist",
23
23
  "test": "vitest run",
24
+ "test:unit": "yarn test",
24
25
  "lint": "oxlint --import-plugin src test features stories",
25
26
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
26
27
  },
27
28
  "dependencies": {
28
- "@allurereport/ci": "3.20.1",
29
- "@allurereport/cli-commons": "3.20.1",
30
- "@allurereport/core-api": "3.20.1",
31
- "@allurereport/plugin-agent": "3.20.1",
32
- "@allurereport/plugin-allure2": "3.20.1",
33
- "@allurereport/plugin-api": "3.20.1",
34
- "@allurereport/plugin-awesome": "3.20.1",
35
- "@allurereport/plugin-classic": "3.20.1",
36
- "@allurereport/plugin-csv": "3.20.1",
37
- "@allurereport/plugin-dashboard": "3.20.1",
38
- "@allurereport/plugin-jira": "3.20.1",
39
- "@allurereport/plugin-log": "3.20.1",
40
- "@allurereport/plugin-progress": "3.20.1",
41
- "@allurereport/plugin-slack": "3.20.1",
42
- "@allurereport/plugin-testops": "3.20.1",
43
- "@allurereport/plugin-testplan": "3.20.1",
44
- "@allurereport/reader": "3.20.1",
45
- "@allurereport/reader-api": "3.20.1",
46
- "@allurereport/service": "3.20.1",
47
- "@allurereport/summary": "3.20.1",
29
+ "@allurereport/ci": "3.21.0",
30
+ "@allurereport/cli-commons": "3.21.0",
31
+ "@allurereport/core-api": "3.21.0",
32
+ "@allurereport/plugin-agent": "3.21.0",
33
+ "@allurereport/plugin-allure2": "3.21.0",
34
+ "@allurereport/plugin-api": "3.21.0",
35
+ "@allurereport/plugin-awesome": "3.21.0",
36
+ "@allurereport/plugin-classic": "3.21.0",
37
+ "@allurereport/plugin-csv": "3.21.0",
38
+ "@allurereport/plugin-dashboard": "3.21.0",
39
+ "@allurereport/plugin-jira": "3.21.0",
40
+ "@allurereport/plugin-log": "3.21.0",
41
+ "@allurereport/plugin-metrics": "3.21.0",
42
+ "@allurereport/plugin-progress": "3.21.0",
43
+ "@allurereport/plugin-slack": "3.21.0",
44
+ "@allurereport/plugin-testops": "3.21.0",
45
+ "@allurereport/plugin-testplan": "3.21.0",
46
+ "@allurereport/plugin-xray": "3.21.0",
47
+ "@allurereport/reader": "3.21.0",
48
+ "@allurereport/reader-api": "3.21.0",
49
+ "@allurereport/service": "3.21.0",
50
+ "@allurereport/summary": "3.21.0",
48
51
  "glob": "^13.0.6",
49
- "handlebars": "^4.7.9",
52
+ "handlebars": "4.7.10",
50
53
  "jiti": "^2.5.1",
51
54
  "node-stream-zip": "^1.15.0",
52
55
  "p-limit": "^7.3.0",
@@ -55,8 +58,10 @@
55
58
  "zip-stream": "^7.0.5"
56
59
  },
57
60
  "devDependencies": {
61
+ "@allurereport/test-config": "3.21.0",
58
62
  "@types/node": "^20",
59
63
  "@types/zip-stream": "^7.0.0",
64
+ "@vitest/coverage-istanbul": "^4.1.0",
60
65
  "@vitest/runner": "^2",
61
66
  "@vitest/snapshot": "^5.0.1",
62
67
  "allure-js-commons": "^3",