@allurereport/core 3.18.0 → 3.19.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,9 +1,19 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { findByLabelName, notNull } from "@allurereport/core-api";
2
+ import { UNKNOWN_PARAMETER_VALUE, calculateParametersHash, calculateRetryHash, calculateTestCaseHash, findByLabelName, notNull, } from "@allurereport/core-api";
3
3
  import { md5 } from "@allurereport/plugin-api";
4
4
  import { extension, lookupContentType } from "@allurereport/reader-api";
5
5
  const defaultStatus = "unknown";
6
- export const __unknown = "#___unknown_value___#";
6
+ const convertRawError = (raw) => ({
7
+ message: raw.message,
8
+ trace: raw.trace,
9
+ ...(raw.actual && raw.expected ? { expected: raw.expected, actual: raw.actual } : {}),
10
+ });
11
+ const convertTestErrors = (raw) => {
12
+ const errors = raw.errors?.filter(notNull);
13
+ if (errors?.length) {
14
+ return errors.map(convertRawError);
15
+ }
16
+ };
7
17
  export const testFixtureResultRawToState = (stateData, raw, context) => {
8
18
  const name = raw.name || "Unknown test";
9
19
  return {
@@ -26,24 +36,32 @@ export const testFixtureResultRawToState = (stateData, raw, context) => {
26
36
  };
27
37
  };
28
38
  export const testResultRawToState = (stateData, raw, context) => {
39
+ const legacyTestCaseHash = calculateLegacyTestCaseHash(raw);
40
+ const allureId = raw.labels
41
+ ?.find((label) => (label?.name === "ALLURE_ID" || label?.name === "AS_ID") && label.value?.trim())
42
+ ?.value?.trim();
29
43
  const labels = convertLabels(raw.labels);
30
44
  const hostId = findByLabelName(labels, "host");
31
45
  const threadId = findByLabelName(labels, "thread");
32
46
  const name = raw.name || "Unknown test";
33
- const testCase = processTestCase(stateData, raw);
34
47
  const parameters = convertParameters(raw.parameters);
48
+ const error = convertRawError(raw);
49
+ const errors = convertTestErrors(raw);
50
+ const testCaseHash = calculateTestCaseHash(raw.testId, raw.fullName);
51
+ const parametersHash = calculateParametersHash(parameters);
52
+ const testCase = processTestCase({ stateData, raw, allureId, testCaseHash });
35
53
  return {
36
54
  id: md5(raw.uuid || randomUUID()),
37
55
  name,
38
56
  testCase,
39
57
  fullName: raw.fullName,
40
- historyId: calculateHistoryId(testCase, parameters),
58
+ testCaseHash,
59
+ parametersHash,
60
+ environmentHash: null,
61
+ retryHash: calculateRetryHash({ testCaseHash, parametersHash }),
41
62
  status: raw.status ?? defaultStatus,
42
- error: {
43
- message: raw.message,
44
- trace: raw.trace,
45
- ...(raw.actual && raw.expected ? { expected: raw.expected, actual: raw.actual } : {}),
46
- },
63
+ error: errors?.[0] ?? error,
64
+ errors,
47
65
  ...processTimings(raw),
48
66
  description: raw.description,
49
67
  descriptionHtml: raw.descriptionHtml,
@@ -64,25 +82,43 @@ export const testResultRawToState = (stateData, raw, context) => {
64
82
  sourceMetadata: {
65
83
  readerId: context.readerId,
66
84
  metadata: context.metadata ?? {},
85
+ legacyHistoryId: raw.historyId?.length ? raw.historyId : undefined,
86
+ reportedFlaky: raw.flaky ?? false,
87
+ legacyTestCaseHash,
67
88
  },
68
89
  titlePath: raw.titlePath ?? [],
69
90
  };
70
91
  };
71
- const processTestCase = ({ testCases }, raw) => {
72
- const [id, allureId] = calculateTestId(raw);
73
- if (id) {
74
- const maybeTestCase = testCases.get(id);
92
+ const calculateLegacyTestCaseHash = (raw) => {
93
+ const maybeAllureId = raw.labels?.find((label) => (label?.name === "ALLURE_ID" || label?.name === "AS_ID") && label.value !== "-1")?.value;
94
+ if (maybeAllureId) {
95
+ return md5(`ALLURE_ID=${maybeAllureId}`);
96
+ }
97
+ if (raw.testId) {
98
+ return md5(raw.testId);
99
+ }
100
+ if (raw.fullName) {
101
+ return md5(raw.fullName);
102
+ }
103
+ return undefined;
104
+ };
105
+ const processTestCase = ({ stateData: { testCases }, raw, allureId, testCaseHash, }) => {
106
+ if (testCaseHash) {
107
+ const maybeTestCase = testCases.get(testCaseHash);
75
108
  if (maybeTestCase) {
109
+ if (!maybeTestCase.allureId && allureId) {
110
+ maybeTestCase.allureId = allureId;
111
+ }
76
112
  return maybeTestCase;
77
113
  }
78
114
  const testCase = {
79
- id,
115
+ id: testCaseHash,
80
116
  allureId,
81
117
  externalId: raw.testId,
82
- name: raw.testCaseName ?? raw.name ?? __unknown,
118
+ name: raw.testCaseName ?? raw.name ?? UNKNOWN_PARAMETER_VALUE,
83
119
  fullName: raw.fullName,
84
120
  };
85
- testCases.set(id, testCase);
121
+ testCases.set(testCaseHash, testCase);
86
122
  return testCase;
87
123
  }
88
124
  return undefined;
@@ -100,7 +136,7 @@ const processAttachmentLink = ({ attachments, visitAttachmentLink }, attach) =>
100
136
  originalFileName: undefined,
101
137
  contentType: attach.contentType,
102
138
  ext: "",
103
- name: attach.name ?? __unknown,
139
+ name: attach.name ?? UNKNOWN_PARAMETER_VALUE,
104
140
  missed: true,
105
141
  used: true,
106
142
  });
@@ -128,7 +164,7 @@ const processAttachmentLink = ({ attachments, visitAttachmentLink }, attach) =>
128
164
  id: randomUUID(),
129
165
  originalFileName: undefined,
130
166
  ext: "",
131
- name: attach.name ?? attach.originalFileName ?? __unknown,
167
+ name: attach.name ?? attach.originalFileName ?? UNKNOWN_PARAMETER_VALUE,
132
168
  contentType: attach.contentType,
133
169
  missed: true,
134
170
  used: true,
@@ -165,11 +201,11 @@ const processTimings = ({ start, stop, duration, }) => {
165
201
  return { start: undefined, stop: undefined, duration };
166
202
  };
167
203
  const convertLabels = (labels) => {
168
- return labels?.filter(notNull)?.map(convertLabel)?.flatMap(processTagLabels) ?? [];
204
+ return labels?.filter(notNull)?.map(convertLabel)?.flatMap(processTagLabels).map(normalizeAllureIdLabel) ?? [];
169
205
  };
170
206
  const convertLabel = (label) => {
171
207
  return {
172
- name: label.name ?? __unknown,
208
+ name: label.name ?? UNKNOWN_PARAMETER_VALUE,
173
209
  value: label.value,
174
210
  };
175
211
  };
@@ -196,7 +232,7 @@ const convertStep = (stateData, step) => {
196
232
  return {
197
233
  convertedStep: {
198
234
  stepId: md5(`${step.name}${step.start}`),
199
- name: step.name ?? __unknown,
235
+ name: step.name ?? UNKNOWN_PARAMETER_VALUE,
200
236
  status: step.status ?? defaultStatus,
201
237
  steps: subSteps,
202
238
  parameters: convertParameters(step.parameters),
@@ -217,11 +253,11 @@ const convertStep = (stateData, step) => {
217
253
  };
218
254
  const convertParameters = (parameters) => parameters
219
255
  ?.filter(notNull)
220
- ?.filter((p) => p.name)
256
+ ?.filter((p) => typeof p.name === "string" && p.name.length > 0)
221
257
  ?.map(convertParameter) ?? [];
222
258
  const convertParameter = (param) => ({
223
- name: param.name ?? __unknown,
224
- value: param.value ?? __unknown,
259
+ name: param.name ?? UNKNOWN_PARAMETER_VALUE,
260
+ value: param.value ?? UNKNOWN_PARAMETER_VALUE,
225
261
  hidden: param.hidden ?? false,
226
262
  excluded: param.excluded ?? false,
227
263
  masked: param.masked ?? false,
@@ -232,42 +268,9 @@ const convertLinks = (links) => links
232
268
  ?.map(convertLink) ?? [];
233
269
  const convertLink = (link) => ({
234
270
  name: link.name,
235
- url: link.url ?? __unknown,
271
+ url: link.url ?? UNKNOWN_PARAMETER_VALUE,
236
272
  type: link.type,
237
273
  });
238
- const calculateTestId = (raw) => {
239
- const maybeAllureId = raw.labels?.find((label) => (label.name === "ALLURE_ID" || label.name === "AS_ID") && label.value !== "-1")?.value;
240
- if (maybeAllureId) {
241
- return [md5(`ALLURE_ID=${maybeAllureId}`), maybeAllureId];
242
- }
243
- if (raw.testId) {
244
- return [md5(raw.testId), undefined];
245
- }
246
- if (raw.fullName) {
247
- return [md5(raw.fullName), undefined];
248
- }
249
- return [undefined, undefined];
250
- };
251
- const calculateHistoryId = (testCase, parameters) => {
252
- if (!testCase) {
253
- return undefined;
254
- }
255
- const paramsPart = stringifyParams(parameters);
256
- return `${testCase.id}.${md5(paramsPart)}`;
257
- };
258
- const parametersCompare = (a, b) => {
259
- return (a.name ?? "").localeCompare(b.name) || a.value.localeCompare(b.value ?? "");
260
- };
261
- const stringifyParams = (parameters) => {
262
- if (!parameters) {
263
- return "";
264
- }
265
- return parameters
266
- .filter((p) => !p?.excluded)
267
- .sort(parametersCompare)
268
- .map((p) => `${p.name}:${p.value}`)
269
- .join(",");
270
- };
271
274
  const idLabelMatcher = new RegExp("^@?allure\\.id[:=](?<id>.+)$");
272
275
  const tagLabelMatcher = new RegExp("^@?allure\\.label\\.(?<name>.+)[:=](?<value>.+)$");
273
276
  const processTagLabels = (label) => {
@@ -286,3 +289,13 @@ const processTagLabels = (label) => {
286
289
  }
287
290
  return label.name ? [{ name: label.name, value: label.value }] : [];
288
291
  };
292
+ const normalizeAllureIdLabel = (label) => {
293
+ if (label.name !== "ALLURE_ID" && label.name !== "AS_ID") {
294
+ return label;
295
+ }
296
+ const value = label.value?.trim();
297
+ return {
298
+ name: "ALLURE_ID",
299
+ value: value?.length ? value : undefined,
300
+ };
301
+ };
@@ -1,6 +1,4 @@
1
- import type { TestParameter, TestResult } from "@allurereport/core-api";
2
- export declare const calculateParametersHash: (parameters?: TestParameter[]) => string;
3
- export declare const calculateRetryHash: (testCaseId: string | undefined, parametersHash: string, environmentId: string | undefined) => string | undefined;
1
+ import type { TestResult } from "@allurereport/core-api";
4
2
  export declare class RetrySubstore {
5
3
  #private;
6
4
  recordIngestOrder(testResultId: string): void;
@@ -4,21 +4,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
6
  var _RetrySubstore_instances, _RetrySubstore_testResultsByRetryHash, _RetrySubstore_testResultIngestIndexById, _RetrySubstore_getIngestIndex, _RetrySubstore_compareResults;
7
- import { md5 } from "../utils/crypto.js";
8
7
  const NO_RETRIES = [];
9
- const compareByNameThenValue = (first, second) => first.name.localeCompare(second.name) || first.value.localeCompare(second.value);
10
- const stringifyRetryParameters = (parameters = []) => parameters
11
- .filter((parameter) => !parameter.excluded)
12
- .sort(compareByNameThenValue)
13
- .map((parameter) => `${parameter.name}:${parameter.value}`)
14
- .join(",");
15
- export const calculateParametersHash = (parameters = []) => md5(stringifyRetryParameters(parameters));
16
- export const calculateRetryHash = (testCaseId, parametersHash, environmentId) => {
17
- if (!testCaseId) {
18
- return undefined;
19
- }
20
- return md5(`${testCaseId}:${parametersHash}:${environmentId ?? "default"}`);
21
- };
22
8
  export class RetrySubstore {
23
9
  constructor() {
24
10
  _RetrySubstore_instances.add(this);
@@ -1,4 +1,4 @@
1
- import { type AllureCheckResult, type AllureHistory, type AllurePerformanceResult, type AttachmentLink, type DefaultLabelsConfig, type EnvironmentIdentity, type EnvironmentsConfig, type GlobalAttachmentLink, type HistoryDataPoint, type HistoryTestResult, type ResolutionIssue, type ResolutionsConfig, type MetricSample, type PerformanceConfig, type ReportVariables, type Statistic, type TestCase, type TestEnvGroup, type TestError, type TestFixtureResult, type TestResult } from "@allurereport/core-api";
1
+ import { type AllureCheckResult, type AllureHistory, type AllurePerformanceResult, type AttachmentLink, type DefaultLabelsConfig, type EnvironmentIdentity, type EnvironmentsConfig, type FlakyDetectionConfig, type GlobalAttachmentLink, type HistoryDataPoint, type HistoryTestResult, type ResolutionIssue, type ResolutionsConfig, type MetricSample, type PerformanceConfig, type ReportVariables, type Statistic, type TestCase, type TestEnvGroup, type TestError, type TestFixtureResult, type TestResult } from "@allurereport/core-api";
2
2
  import { type AllureStore, type AllureStoreDump, type ExitCode, type PluginGlobalError, type QualityGateValidationResult, type RealtimeEventsDispatcher, type RealtimeSubscriber, type ResultFile, type TestResultFilter } from "@allurereport/plugin-api";
3
3
  import type { RawFixtureResult, RawGlobals, RawMetadata, RawTestResult, ReaderContext, ResultsVisitor } from "@allurereport/reader-api";
4
4
  export declare const mapToObject: <K extends string | number | symbol, T = any>(map: Map<K, T>) => Record<K, T>;
@@ -7,12 +7,13 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
7
7
  #private;
8
8
  readonly indexTestResultByTestCase: Map<string, TestResult[]>;
9
9
  readonly indexTestResultByEnvironmentId: Map<string, TestResult[]>;
10
- readonly indexTestResultByHistoryId: Map<string, TestResult[]>;
10
+ readonly indexTestResultByRetryHash: Map<string, TestResult[]>;
11
11
  readonly indexAttachmentByTestResult: Map<string, AttachmentLink[]>;
12
12
  readonly indexAttachmentByFixture: Map<string, AttachmentLink[]>;
13
13
  readonly indexFixturesByTestResult: Map<string, TestFixtureResult[]>;
14
14
  constructor(params?: {
15
15
  history?: AllureHistory;
16
+ flakyDetection?: FlakyDetectionConfig;
16
17
  resolutionsConfig?: ResolutionsConfig;
17
18
  realtimeDispatcher?: RealtimeEventsDispatcher;
18
19
  realtimeSubscriber?: RealtimeSubscriber;
@@ -24,6 +25,7 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
24
25
  performance?: PerformanceConfig;
25
26
  });
26
27
  readHistory(): Promise<HistoryDataPoint[]>;
28
+ updateHistoryFlags(testResults?: Iterable<TestResult>): void;
27
29
  appendHistory(history: HistoryDataPoint): Promise<void>;
28
30
  addCheckResult(result: AllureCheckResult): Promise<void>;
29
31
  allCheckResults(): Promise<AllureCheckResult[]>;