@allurereport/core 3.19.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.
package/dist/index.d.ts CHANGED
@@ -11,4 +11,4 @@ export * from "./resolutions.js";
11
11
  export { resolveConfig, readConfig, readRawConfig, getPluginInstance } from "./config.js";
12
12
  export * from "./report.js";
13
13
  export * from "./plugin.js";
14
- export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, metricMaxRule, metricMinRule, metricMaxDeltaRule, metricMaxDeltaPercentRule, convertQualityGateResultsToTestErrors, filterFailedQualityGateResults, stringifyQualityGateResults, } from "./qualityGate/index.js";
14
+ export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, newTestsRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, metricMaxRule, metricMinRule, metricMaxDeltaRule, metricMaxDeltaPercentRule, convertQualityGateResultsToTestErrors, filterFailedQualityGateResults, stringifyQualityGateResults, } from "./qualityGate/index.js";
package/dist/index.js CHANGED
@@ -10,4 +10,4 @@ export * from "./resolutions.js";
10
10
  export { resolveConfig, readConfig, readRawConfig, getPluginInstance } from "./config.js";
11
11
  export * from "./report.js";
12
12
  export * from "./plugin.js";
13
- export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, metricMaxRule, metricMinRule, metricMaxDeltaRule, metricMaxDeltaPercentRule, convertQualityGateResultsToTestErrors, filterFailedQualityGateResults, stringifyQualityGateResults, } from "./qualityGate/index.js";
13
+ export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, newTestsRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, metricMaxRule, metricMinRule, metricMaxDeltaRule, metricMaxDeltaPercentRule, convertQualityGateResultsToTestErrors, filterFailedQualityGateResults, stringifyQualityGateResults, } from "./qualityGate/index.js";
@@ -7,6 +7,7 @@ type MetricRuleConfig = {
7
7
  };
8
8
  export declare const maxFailuresRule: QualityGateRule<number>;
9
9
  export declare const minTestsCountRule: QualityGateRule<number>;
10
+ export declare const newTestsRule: QualityGateRule<boolean, number>;
10
11
  export declare const successRateRule: QualityGateRule<number>;
11
12
  export declare const maxDurationRule: QualityGateRule<number>;
12
13
  export declare const allTestsContainEnvRule: QualityGateRule<string, number>;
@@ -15,5 +16,5 @@ export declare const metricMaxRule: QualityGateRule<MetricRuleConfig>;
15
16
  export declare const metricMinRule: QualityGateRule<MetricRuleConfig>;
16
17
  export declare const metricMaxDeltaRule: QualityGateRule<MetricRuleConfig>;
17
18
  export declare const metricMaxDeltaPercentRule: QualityGateRule<MetricRuleConfig>;
18
- export declare const qualityGateDefaultRules: (QualityGateRule<number> | QualityGateRule<string, number> | QualityGateRule<string[]> | QualityGateRule<MetricRuleConfig>)[];
19
+ export declare const qualityGateDefaultRules: (QualityGateRule<number> | QualityGateRule<boolean, number> | QualityGateRule<string, number> | QualityGateRule<string[]> | QualityGateRule<MetricRuleConfig>)[];
19
20
  export {};
@@ -106,6 +106,25 @@ export const minTestsCountRule = {
106
106
  };
107
107
  },
108
108
  };
109
+ export const newTestsRule = {
110
+ rule: "newTests",
111
+ message: ({ actual, expected }) => expected
112
+ ? `No new tests were found; expected at least one new test`
113
+ : `The number of new tests ${bold(String(actual))} does not match the expected policy`,
114
+ successMessage: ({ actual }) => `New tests were found: ${bold(String(actual))}`,
115
+ validate: async ({ trs, expected, state }) => {
116
+ const previous = numberStateValue(state.getResult());
117
+ const newTrs = trs.filter((tr) => tr.transition === "new");
118
+ const testResults = newTrs.map((tr) => tr.id);
119
+ const actual = previous + newTrs.length;
120
+ state.setResult(actual, testResults);
121
+ return {
122
+ success: !expected || actual > 0,
123
+ actual,
124
+ testResults,
125
+ };
126
+ },
127
+ };
109
128
  export const successRateRule = {
110
129
  rule: "successRate",
111
130
  message: ({ actual, expected }) => `Success rate ${bold(formatQualityGateNumber(actual))} is less, than expected ${bold(formatQualityGateNumber(expected))}`,
@@ -237,6 +256,7 @@ export const metricMaxDeltaPercentRule = {
237
256
  export const qualityGateDefaultRules = [
238
257
  maxFailuresRule,
239
258
  minTestsCountRule,
259
+ newTestsRule,
240
260
  successRateRule,
241
261
  maxDurationRule,
242
262
  allTestsContainEnvRule,
package/dist/report.js CHANGED
@@ -22,7 +22,7 @@ import { detect } from "@allurereport/ci";
22
22
  import { createProgressLogger } from "@allurereport/cli-commons";
23
23
  import { normalizeCategoriesConfig, parseIntegerConfigValue } from "@allurereport/core-api";
24
24
  import { AllureStoreDumpFiles, createTestResultRegistry, } from "@allurereport/plugin-api";
25
- import { allure1, allure2, attachments, cucumberjson, junitXml, readXcResultBundle } from "@allurereport/reader";
25
+ import { allure1, allure2, attachments, cucumberjson, cucumberMessages, junitXml, readXcResultBundle, } from "@allurereport/reader";
26
26
  import { PathResultFile } from "@allurereport/reader-api";
27
27
  import { AllureRemoteHistory, AllureServiceClient, AllureTestOpsClient, KnownError, UnknownError, } from "@allurereport/service";
28
28
  import { generateSummary } from "@allurereport/summary";
@@ -37,7 +37,7 @@ import { writeKnownIssues } from "./resolutions.js";
37
37
  import { DefaultAllureStore } from "./store/store.js";
38
38
  import { ARTIFACTS_MANIFEST_FILENAME, createReportArtifact, deduplicateDumpInputs, } from "./utils/artifacts.js";
39
39
  import { environmentIdentityById, environmentIdentityByName } from "./utils/environment.js";
40
- import { getPerfMetricsResults, isPerfMetricsEnabled, measurePerf, PERF_METRIC_NAMES, PERF_METRIC_PREFIXES, perfMetricsFileName, startPerfSpan, writePerfMetrics, } from "./utils/perf.js";
40
+ import { getPerfMetricsResults, incrementPerfCounter, isPerfMetricsEnabled, measurePerfAggregate, measurePerf, PERF_METRIC_NAMES, PERF_METRIC_PREFIXES, perfMetricsFileName, startPerfSpan, writePerfMetrics, } from "./utils/perf.js";
41
41
  import { RealtimeChannel } from "./utils/realtimeChannel.js";
42
42
  import { RealtimeUpdateScheduler } from "./utils/realtimeUpdateScheduler.js";
43
43
  import { resolveDumpAttachmentPath, UnsafeDumpPathError } from "./utils/safeDumpPath.js";
@@ -53,6 +53,11 @@ const ROOT_INTEGRATION_FILENAMES = new Set([
53
53
  QUALITY_GATE_RESULTS_FILENAME,
54
54
  ARTIFACTS_MANIFEST_FILENAME,
55
55
  ]);
56
+ const WORKLOAD_PERF_METRIC = {
57
+ group: "workload",
58
+ groupTitle: "Workload",
59
+ better: "neutral",
60
+ };
56
61
  const readConcurrency = () => {
57
62
  const parsed = Number.parseInt(process.env.ALLURE_READ_CONCURRENCY ?? "", 10);
58
63
  if (!Number.isFinite(parsed)) {
@@ -298,18 +303,23 @@ export class AllureReport {
298
303
  throw new Error(INIT_REQUIRED_ERROR_MESSAGE);
299
304
  }
300
305
  const resultsDirPath = resolve(resultsDir);
301
- if (await readXcResultBundle(__classPrivateFieldGet(this, _AllureReport_store, "f"), resultsDirPath)) {
306
+ if (await measurePerf(PERF_METRIC_NAMES.generateReadResultsXcresultCheck, () => readXcResultBundle(__classPrivateFieldGet(this, _AllureReport_store, "f"), resultsDirPath))) {
302
307
  __classPrivateFieldGet(this, _AllureReport_store, "f").updateHistoryFlags();
303
308
  return;
304
309
  }
305
310
  try {
306
- const entries = (await readdir(resultsDirPath, { withFileTypes: true }))
311
+ const entries = await measurePerf(PERF_METRIC_NAMES.generateReadResultsReaddir, async () => (await readdir(resultsDirPath, { withFileTypes: true }))
307
312
  .filter((dirent) => dirent.isFile() && !dirent.name.endsWith(".tmp"))
308
- .sort((a, b) => a.name.localeCompare(b.name));
313
+ .sort((a, b) => a.name.localeCompare(b.name)));
309
314
  const limit = pLimit(readConcurrency());
315
+ incrementPerfCounter(PERF_METRIC_NAMES.generateReadResultsFiles, entries.length, {
316
+ ...WORKLOAD_PERF_METRIC,
317
+ title: "Input files",
318
+ unit: "files",
319
+ });
310
320
  await Promise.all(entries.map((dirent) => limit(async () => {
311
321
  try {
312
- const path = await realpath(join(resultsDirPath, dirent.name));
322
+ const path = await measurePerfAggregate(PERF_METRIC_NAMES.generateReadResultsRealpath, () => realpath(join(resultsDirPath, dirent.name)));
313
323
  await this.readResult(new PathResultFile(path, dirent.name));
314
324
  }
315
325
  catch (e) {
@@ -338,7 +348,7 @@ export class AllureReport {
338
348
  if (reader.matches && !(await reader.matches(data))) {
339
349
  continue;
340
350
  }
341
- const processed = await reader.read(__classPrivateFieldGet(this, _AllureReport_store, "f"), data);
351
+ const processed = await measurePerfAggregate(PERF_METRIC_NAMES.generateReadResultsReaderRead, () => reader.read(__classPrivateFieldGet(this, _AllureReport_store, "f"), data));
342
352
  if (processed) {
343
353
  return;
344
354
  }
@@ -457,7 +467,7 @@ export class AllureReport {
457
467
  const addJsonDumpEntry = async (entryName, value) => {
458
468
  await addRequiredDumpEntry(Buffer.from(JSON.stringify(value)), entryName);
459
469
  };
460
- const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = {}, globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByRetryHash = {}, indexTestResultByTestCase = {}, indexTestResultByResolutionIssue = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, resolutionIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], metrics = [], }) => [
470
+ const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, metadata = {}, checkResults = {}, globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByRetryHash = {}, indexTestResultByTestCase = {}, indexTestResultByResolutionIssue = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, resolutionIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], metrics = [], }) => [
461
471
  [AllureStoreDumpFiles.TestResults, testResults],
462
472
  [AllureStoreDumpFiles.TestCases, testCases],
463
473
  [AllureStoreDumpFiles.Fixtures, fixtures],
@@ -465,6 +475,7 @@ export class AllureReport {
465
475
  [AllureStoreDumpFiles.CheckResults, checkResults],
466
476
  [AllureStoreDumpFiles.Environments, environments],
467
477
  [AllureStoreDumpFiles.ReportVariables, reportVariables],
478
+ [AllureStoreDumpFiles.Metadata, metadata],
468
479
  [AllureStoreDumpFiles.ResolutionIssues, resolutionIssues],
469
480
  [AllureStoreDumpFiles.GlobalAttachments, globalAttachmentIds],
470
481
  [AllureStoreDumpFiles.GlobalErrors, globalErrors],
@@ -613,6 +624,7 @@ export class AllureReport {
613
624
  const checkResultsEntry = await optionalEntryData(AllureStoreDumpFiles.CheckResults);
614
625
  const environmentsEntry = await requiredEntryData(AllureStoreDumpFiles.Environments);
615
626
  const reportVariablesEntry = await requiredEntryData(AllureStoreDumpFiles.ReportVariables);
627
+ const metadataEntry = await optionalEntryData(AllureStoreDumpFiles.Metadata);
616
628
  const globalAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.GlobalAttachments);
617
629
  const globalErrorsEntry = await requiredEntryData(AllureStoreDumpFiles.GlobalErrors);
618
630
  const indexAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByTestResults);
@@ -633,6 +645,7 @@ export class AllureReport {
633
645
  case AllureStoreDumpFiles.Fixtures:
634
646
  case AllureStoreDumpFiles.Environments:
635
647
  case AllureStoreDumpFiles.ReportVariables:
648
+ case AllureStoreDumpFiles.Metadata:
636
649
  case AllureStoreDumpFiles.ResolutionIssues:
637
650
  case AllureStoreDumpFiles.GlobalAttachments:
638
651
  case AllureStoreDumpFiles.GlobalErrors:
@@ -663,6 +676,7 @@ export class AllureReport {
663
676
  checkResults: checkResultsEntry ? JSON.parse(checkResultsEntry.toString("utf8")) : [],
664
677
  environments: JSON.parse(environmentsEntry.toString("utf8")),
665
678
  reportVariables: JSON.parse(reportVariablesEntry.toString("utf8")),
679
+ metadata: metadataEntry ? JSON.parse(metadataEntry.toString("utf8")) : {},
666
680
  globalAttachmentIds: JSON.parse(globalAttachmentsEntry.toString("utf8")),
667
681
  globalErrors: JSON.parse(globalErrorsEntry.toString("utf8")),
668
682
  indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
@@ -978,6 +992,11 @@ export class AllureReport {
978
992
  await pluginState.set("files", {});
979
993
  }
980
994
  const pluginFiles = new PluginFiles(__classPrivateFieldGet(this, _AllureReport_reportFiles, "f"), id, async (key, filepath) => {
995
+ incrementPerfCounter(`${PERF_METRIC_PREFIXES.generatePlugin}${id}.generatedFiles`, 1, {
996
+ ...WORKLOAD_PERF_METRIC,
997
+ title: `Generated ${id} files`,
998
+ unit: "files",
999
+ });
981
1000
  const currentPluginState = __classPrivateFieldGet(this, _AllureReport_instances, "m", _AllureReport_getPluginState).call(this, false, id);
982
1001
  const files = await currentPluginState?.get("files");
983
1002
  if (!files) {
@@ -994,6 +1013,14 @@ export class AllureReport {
994
1013
  hideLabels: __classPrivateFieldGet(this, _AllureReport_hideLabels, "f"),
995
1014
  state: pluginState,
996
1015
  reportFiles: pluginFiles,
1016
+ ...(isPerfMetricsEnabled()
1017
+ ? {
1018
+ perf: {
1019
+ measure: (name, fn) => measurePerf(`${PERF_METRIC_PREFIXES.generatePlugin}${id}.${name}`, fn),
1020
+ count: (name, value, metadata) => incrementPerfCounter(`${PERF_METRIC_PREFIXES.generatePlugin}${id}.${name}`, value, metadata),
1021
+ },
1022
+ }
1023
+ : {}),
997
1024
  reportUrl: this.reportUrl,
998
1025
  realTime: !!__classPrivateFieldGet(this, _AllureReport_realTime, "f"),
999
1026
  output: __classPrivateFieldGet(this, _AllureReport_output, "f"),
@@ -1013,7 +1040,7 @@ export class AllureReport {
1013
1040
  }
1014
1041
  }
1015
1042
  });
1016
- const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], resolutions, reportFiles, realTime, historyPath, historyBaseUrl, historyLimit, flakyDetection, appendHistory, defaultLabels = {}, variables = {}, environment, allowedEnvironments, environments, output, hideLabels, qualityGate, performance, dump, categories, allureService, globalAttachments, cwd, } = opts;
1043
+ const { name, readers = [allure1, allure2, cucumberjson, cucumberMessages, junitXml, attachments], plugins = [], resolutions, reportFiles, realTime, historyPath, historyBaseUrl, historyLimit, flakyDetection, appendHistory, defaultLabels = {}, variables = {}, environment, allowedEnvironments, environments, output, hideLabels, qualityGate, performance, dump, categories, allureService, globalAttachments, cwd, } = opts;
1017
1044
  const allureServiceAccessToken = allureService?.accessToken;
1018
1045
  if (allureServiceAccessToken) {
1019
1046
  const allureServiceClientConfig = {
@@ -17,6 +17,7 @@ import { getResolutionByRules, isIgnoredFailure } from "../resolutions.js";
17
17
  import { environmentIdentityById, normalizeEnvironmentDescriptorMap, resolveEnvironmentIdentity, resolveStoredEnvironmentIdentity, validateAllowedEnvironmentId, } from "../utils/environment.js";
18
18
  import { createFlakyDetector } from "../utils/flaky.js";
19
19
  import { getStatusTransition } from "../utils/new.js";
20
+ import { measurePerfAggregateSync, PERF_METRIC_NAMES } from "../utils/perf.js";
20
21
  import { testFixtureResultRawToState, testResultRawToState } from "./convert.js";
21
22
  import { RetrySubstore } from "./retrySubstore.js";
22
23
  const index = (indexMap, key, ...items) => {
@@ -348,58 +349,71 @@ export class DefaultAllureStore {
348
349
  }
349
350
  async visitTestResult(raw, context) {
350
351
  const attachmentLinks = [];
351
- const testResult = testResultRawToState({
352
+ const testResult = measurePerfAggregateSync(PERF_METRIC_NAMES.storeVisitTestResultConvert, () => testResultRawToState({
352
353
  testCases: __classPrivateFieldGet(this, _DefaultAllureStore_testCases, "f"),
353
354
  attachments: __classPrivateFieldGet(this, _DefaultAllureStore_attachments, "f"),
354
355
  visitAttachmentLink: (link) => attachmentLinks.push(link),
355
- }, raw, context);
356
- const defaultLabelsNames = Object.keys(__classPrivateFieldGet(this, _DefaultAllureStore_defaultLabels, "f"));
357
- if (defaultLabelsNames.length) {
358
- defaultLabelsNames.forEach((labelName) => {
359
- if (!testResult.labels.find((label) => label.name === labelName)) {
360
- const defaultLabelValue = __classPrivateFieldGet(this, _DefaultAllureStore_defaultLabels, "f")[labelName];
361
- [].concat(defaultLabelValue).forEach((labelValue) => {
362
- testResult.labels.push({
363
- name: labelName,
364
- value: labelValue,
356
+ }, raw, context));
357
+ measurePerfAggregateSync(PERF_METRIC_NAMES.storeVisitTestResultDefaultLabels, () => {
358
+ const defaultLabelsNames = Object.keys(__classPrivateFieldGet(this, _DefaultAllureStore_defaultLabels, "f"));
359
+ if (defaultLabelsNames.length) {
360
+ defaultLabelsNames.forEach((labelName) => {
361
+ if (!testResult.labels.find((label) => label.name === labelName)) {
362
+ const defaultLabelValue = __classPrivateFieldGet(this, _DefaultAllureStore_defaultLabels, "f")[labelName];
363
+ [].concat(defaultLabelValue).forEach((labelValue) => {
364
+ testResult.labels.push({
365
+ name: labelName,
366
+ value: labelValue,
367
+ });
365
368
  });
366
- });
367
- }
369
+ }
370
+ });
371
+ }
372
+ });
373
+ const environmentIdentity = measurePerfAggregateSync(PERF_METRIC_NAMES.storeVisitTestResultEnvironment, () => {
374
+ const environmentMatcherLabels = testResult.labels.filter(({ name }) => name !== "ALLURE_ID" && name !== fallbackTestCaseIdLabelName);
375
+ const environmentMatch = __classPrivateFieldGet(this, _DefaultAllureStore_environment, "f")
376
+ ? undefined
377
+ : Object.entries(__classPrivateFieldGet(this, _DefaultAllureStore_environmentsConfig, "f")).find(([, { matcher }]) => matcher({ labels: environmentMatcherLabels }));
378
+ const namedEnvironmentIdentity = __classPrivateFieldGet(this, _DefaultAllureStore_environment, "f") ??
379
+ (environmentMatch
380
+ ? {
381
+ id: environmentMatch[0],
382
+ name: environmentMatch[1].name ?? environmentMatch[0],
383
+ }
384
+ : undefined);
385
+ const identity = namedEnvironmentIdentity ?? DEFAULT_ENVIRONMENT_IDENTITY;
386
+ testResult.environment = identity.id;
387
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_addEnvironments).call(this, [identity]);
388
+ return identity;
389
+ });
390
+ measurePerfAggregateSync(PERF_METRIC_NAMES.storeVisitTestResultRetry, () => {
391
+ testResult.environmentHash = calculateEnvironmentHash(environmentIdentity.id);
392
+ testResult.retryHash = calculateRetryHash({
393
+ testCaseHash: testResult.testCaseHash,
394
+ parametersHash: testResult.parametersHash,
395
+ environmentHash: testResult.environmentHash,
368
396
  });
369
- }
370
- const environmentMatcherLabels = testResult.labels.filter(({ name }) => name !== "ALLURE_ID" && name !== fallbackTestCaseIdLabelName);
371
- const environmentMatch = __classPrivateFieldGet(this, _DefaultAllureStore_environment, "f")
372
- ? undefined
373
- : Object.entries(__classPrivateFieldGet(this, _DefaultAllureStore_environmentsConfig, "f")).find(([, { matcher }]) => matcher({ labels: environmentMatcherLabels }));
374
- const namedEnvironmentIdentity = __classPrivateFieldGet(this, _DefaultAllureStore_environment, "f") ??
375
- (environmentMatch
376
- ? {
377
- id: environmentMatch[0],
378
- name: environmentMatch[1].name ?? environmentMatch[0],
379
- }
380
- : undefined);
381
- const environmentIdentity = namedEnvironmentIdentity ?? DEFAULT_ENVIRONMENT_IDENTITY;
382
- testResult.environment = environmentIdentity.id;
383
- __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_addEnvironments).call(this, [environmentIdentity]);
384
- testResult.environmentHash = calculateEnvironmentHash(environmentIdentity.id);
385
- testResult.retryHash = calculateRetryHash({
386
- testCaseHash: testResult.testCaseHash,
387
- parametersHash: testResult.parametersHash,
388
- environmentHash: testResult.environmentHash,
389
397
  });
390
398
  if (__classPrivateFieldGet(this, _DefaultAllureStore_history, "f")) {
391
- const lookup = createHistoryTestResultLookup([testResult]);
392
- __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_applyHistoryFlags).call(this, testResult, __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_historyFor).call(this, testResult, lookup));
399
+ measurePerfAggregateSync(PERF_METRIC_NAMES.storeVisitTestResultHistory, () => {
400
+ const lookup = createHistoryTestResultLookup([testResult]);
401
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_applyHistoryFlags).call(this, testResult, __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_historyFor).call(this, testResult, lookup));
402
+ });
393
403
  }
394
- __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_classifyResolution).call(this, testResult);
395
- __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").set(testResult.id, testResult);
396
- __classPrivateFieldSet(this, _DefaultAllureStore_historyLookup, undefined, "f");
397
- __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_setTestResultEnvironmentId).call(this, testResult, environmentIdentity.id);
398
- __classPrivateFieldGet(this, _DefaultAllureStore_retrySubstore, "f").recordIngestOrder(testResult.id);
399
- __classPrivateFieldGet(this, _DefaultAllureStore_retrySubstore, "f").upsert(testResult);
400
- index(this.indexTestResultByTestCase, testResult.testCase?.id, testResult);
401
- index(this.indexTestResultByRetryHash, testResult.retryHash, testResult);
402
- index(this.indexAttachmentByTestResult, testResult.id, ...attachmentLinks);
404
+ measurePerfAggregateSync(PERF_METRIC_NAMES.storeVisitTestResultResolution, () => {
405
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_classifyResolution).call(this, testResult);
406
+ });
407
+ measurePerfAggregateSync(PERF_METRIC_NAMES.storeVisitTestResultIndexes, () => {
408
+ __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").set(testResult.id, testResult);
409
+ __classPrivateFieldSet(this, _DefaultAllureStore_historyLookup, undefined, "f");
410
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_setTestResultEnvironmentId).call(this, testResult, environmentIdentity.id);
411
+ __classPrivateFieldGet(this, _DefaultAllureStore_retrySubstore, "f").recordIngestOrder(testResult.id);
412
+ __classPrivateFieldGet(this, _DefaultAllureStore_retrySubstore, "f").upsert(testResult);
413
+ index(this.indexTestResultByTestCase, testResult.testCase?.id, testResult);
414
+ index(this.indexTestResultByRetryHash, testResult.retryHash, testResult);
415
+ index(this.indexAttachmentByTestResult, testResult.id, ...attachmentLinks);
416
+ });
403
417
  __classPrivateFieldGet(this, _DefaultAllureStore_realtimeDispatcher, "f")?.sendTestResult(testResult.id);
404
418
  }
405
419
  async visitTestFixtureResult(result, context) {
@@ -416,28 +430,31 @@ export class DefaultAllureStore {
416
430
  __classPrivateFieldGet(this, _DefaultAllureStore_realtimeDispatcher, "f")?.sendTestFixtureResult(testFixtureResult.id);
417
431
  }
418
432
  async visitAttachmentFile(resultFile) {
419
- const originalFileName = resultFile.getOriginalFileName();
420
- const id = md5(originalFileName);
421
- __classPrivateFieldGet(this, _DefaultAllureStore_attachmentContents, "f").set(id, resultFile);
422
- const maybeLink = __classPrivateFieldGet(this, _DefaultAllureStore_attachments, "f").get(id);
423
- if (maybeLink) {
424
- const link = maybeLink;
425
- link.missed = false;
426
- link.ext = link.ext === undefined || link.ext === "" ? resultFile.getExtension() : link.ext;
427
- link.contentType = link.contentType ?? resultFile.getContentType();
428
- link.contentLength = resultFile.getContentLength();
429
- }
430
- else {
431
- __classPrivateFieldGet(this, _DefaultAllureStore_attachments, "f").set(id, {
432
- used: false,
433
- missed: false,
434
- id,
435
- originalFileName,
436
- ext: resultFile.getExtension(),
437
- contentType: resultFile.getContentType(),
438
- contentLength: resultFile.getContentLength(),
439
- });
440
- }
433
+ const { id, originalFileName } = measurePerfAggregateSync(PERF_METRIC_NAMES.storeVisitAttachmentFileMetadata, () => {
434
+ const originalFileName = resultFile.getOriginalFileName();
435
+ const id = md5(originalFileName);
436
+ __classPrivateFieldGet(this, _DefaultAllureStore_attachmentContents, "f").set(id, resultFile);
437
+ const maybeLink = __classPrivateFieldGet(this, _DefaultAllureStore_attachments, "f").get(id);
438
+ if (maybeLink) {
439
+ const link = maybeLink;
440
+ link.missed = false;
441
+ link.ext = link.ext === undefined || link.ext === "" ? resultFile.getExtension() : link.ext;
442
+ link.contentType = link.contentType ?? resultFile.getContentType();
443
+ link.contentLength = resultFile.getContentLength();
444
+ }
445
+ else {
446
+ __classPrivateFieldGet(this, _DefaultAllureStore_attachments, "f").set(id, {
447
+ used: false,
448
+ missed: false,
449
+ id,
450
+ originalFileName,
451
+ ext: resultFile.getExtension(),
452
+ contentType: resultFile.getContentType(),
453
+ contentLength: resultFile.getContentLength(),
454
+ });
455
+ }
456
+ return { id, originalFileName };
457
+ });
441
458
  for (const globalAttachmentId of [...__classPrivateFieldGet(this, _DefaultAllureStore_globalAttachmentIds, "f"), ...__classPrivateFieldGet(this, _DefaultAllureStore_processGlobalAttachmentIds, "f")]) {
442
459
  const globalAttachment = __classPrivateFieldGet(this, _DefaultAllureStore_attachments, "f").get(globalAttachmentId);
443
460
  if (!globalAttachment || globalAttachment.originalFileName !== originalFileName) {
@@ -874,6 +891,7 @@ export class DefaultAllureStore {
874
891
  fixtures: mapToObject(__classPrivateFieldGet(this, _DefaultAllureStore_fixtures, "f")),
875
892
  environments: __classPrivateFieldGet(this, _DefaultAllureStore_environments, "f"),
876
893
  reportVariables: __classPrivateFieldGet(this, _DefaultAllureStore_reportVariables, "f"),
894
+ metadata: mapToObject(__classPrivateFieldGet(this, _DefaultAllureStore_metadata, "f")),
877
895
  globalAttachmentIds: [...__classPrivateFieldGet(this, _DefaultAllureStore_globalAttachmentIds, "f"), ...__classPrivateFieldGet(this, _DefaultAllureStore_processGlobalAttachmentIds, "f")],
878
896
  globalErrors: [...__classPrivateFieldGet(this, _DefaultAllureStore_globalErrors, "f"), ...__classPrivateFieldGet(this, _DefaultAllureStore_processGlobalErrors, "f")],
879
897
  checkResults: mapToObject(__classPrivateFieldGet(this, _DefaultAllureStore_checkResultsById, "f")),
@@ -910,7 +928,7 @@ export class DefaultAllureStore {
910
928
  }
911
929
  async restoreState(stateDump, attachmentsContents = {}) {
912
930
  __classPrivateFieldSet(this, _DefaultAllureStore_historyLookup, undefined, "f");
913
- const { testResults, attachments, testCases, fixtures, reportVariables, environments, globalAttachmentIds = [], globalErrors = [], checkResults, indexAttachmentByTestResult = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, qualityGateResults = [], metrics = [], testResultIdsIngestOrder = [], } = stateDump;
931
+ const { testResults, attachments, testCases, fixtures, reportVariables, metadata = {}, environments, globalAttachmentIds = [], globalErrors = [], checkResults, indexAttachmentByTestResult = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, qualityGateResults = [], metrics = [], testResultIdsIngestOrder = [], } = stateDump;
914
932
  __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f").clear();
915
933
  __classPrivateFieldGet(this, _DefaultAllureStore_testResultIdsByResolutionIssueId, "f").clear();
916
934
  __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssueIdByTestResultId, "f").clear();
@@ -1021,6 +1039,7 @@ export class DefaultAllureStore {
1021
1039
  __classPrivateFieldGet(this, _DefaultAllureStore_globalErrors, "f").push(__classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_indexGlobalError).call(this, error));
1022
1040
  });
1023
1041
  Object.assign(__classPrivateFieldGet(this, _DefaultAllureStore_reportVariables, "f"), reportVariables);
1042
+ updateMapWithRecord(__classPrivateFieldGet(this, _DefaultAllureStore_metadata, "f"), metadata);
1024
1043
  Object.entries(indexAttachmentByTestResult).forEach(([trId, links]) => {
1025
1044
  const attachmentsLinks = links.map((id) => __classPrivateFieldGet(this, _DefaultAllureStore_attachments, "f").get(id)).filter(Boolean);
1026
1045
  if (attachmentsLinks.length === 0) {
@@ -1,18 +1,12 @@
1
1
  import type { AllurePerformanceResult } from "@allurereport/core-api";
2
2
  export declare const PERF_METRICS_FILE = "performance.json";
3
3
  export declare const perfMetricsFileName: (reportUuid: string) => string;
4
- export type PerfMetricSpan = {
5
- name: string;
6
- startTimeMs: number;
7
- durationMs: number;
8
- };
9
- export type PerfMetricSummary = {
10
- name: string;
11
- count: number;
12
- totalMs: number;
13
- minMs: number;
14
- maxMs: number;
15
- avgMs: number;
4
+ type PerfMetricMetadata = {
5
+ title?: string;
6
+ unit?: string;
7
+ group?: string;
8
+ groupTitle?: string;
9
+ better?: "neutral";
16
10
  };
17
11
  export declare const PERF_METRIC_NAMES: {
18
12
  readonly allureTotal: "allure.total";
@@ -22,17 +16,35 @@ export declare const PERF_METRIC_NAMES: {
22
16
  readonly restoreStateStoreRestore: "restoreState.storeRestore";
23
17
  readonly generateTotal: "generate.total";
24
18
  readonly generateReadResults: "generate.readResults";
19
+ readonly generateReadResultsXcresultCheck: "generate.readResults.xcresultCheck";
20
+ readonly generateReadResultsReaddir: "generate.readResults.readdir";
21
+ readonly generateReadResultsFiles: "generate.readResults.files";
22
+ readonly generateReadResultsRealpath: "generate.readResults.realpath";
23
+ readonly generateReadResultsReaderRead: "generate.readResults.reader.read";
25
24
  readonly generatePluginsDone: "generate.plugins.done";
25
+ readonly storeVisitTestResultConvert: "store.visitTestResult.convert";
26
+ readonly storeVisitTestResultDefaultLabels: "store.visitTestResult.defaultLabels";
27
+ readonly storeVisitTestResultEnvironment: "store.visitTestResult.environment";
28
+ readonly storeVisitTestResultRetry: "store.visitTestResult.retry";
29
+ readonly storeVisitTestResultHistory: "store.visitTestResult.history";
30
+ readonly storeVisitTestResultResolution: "store.visitTestResult.resolution";
31
+ readonly storeVisitTestResultIndexes: "store.visitTestResult.indexes";
32
+ readonly storeVisitAttachmentFileMetadata: "store.visitAttachmentFile.metadata";
26
33
  readonly publishUploadTotal: "publish.upload.total";
27
34
  readonly summaryGenerate: "summary.generate";
28
35
  };
29
36
  export declare const PERF_METRIC_PREFIXES: {
37
+ readonly generatePlugin: "generate.plugin.";
30
38
  readonly generatePluginDone: "generate.plugin.done.";
31
39
  readonly publishUploadPlugin: "publish.upload.plugin.";
32
40
  };
33
41
  export declare const isPerfMetricsEnabled: () => boolean;
34
42
  export declare const startPerfSpan: (name: string) => (() => void);
35
43
  export declare const measurePerf: <T>(name: string, fn: () => Promise<T>) => Promise<T>;
44
+ export declare const measurePerfAggregate: <T>(name: string, fn: () => Promise<T>) => Promise<T>;
45
+ export declare const measurePerfAggregateSync: <T>(name: string, fn: () => T) => T;
46
+ export declare const incrementPerfCounter: (name: string, value?: number, metadata?: PerfMetricMetadata) => void;
36
47
  export declare const getPerfMetricsResults: () => AllurePerformanceResult[];
37
48
  export declare const writePerfMetrics: (output: string, fileName?: string) => Promise<boolean>;
38
49
  export declare const resetPerfMetrics: () => void;
50
+ export {};
@@ -7,6 +7,8 @@ export const perfMetricsFileName = (reportUuid) => `${reportUuid}-perf.json`;
7
7
  const MARK_PREFIX = "allure:perf:";
8
8
  const ENABLED_VALUES = new Set(["1", "true", "yes", "on"]);
9
9
  const SPANS = [];
10
+ const AGGREGATES = new Map();
11
+ const COUNTERS = new Map();
10
12
  const MARKS = new Set();
11
13
  const MEASURES = new Set();
12
14
  let sequence = 0;
@@ -19,28 +21,46 @@ export const PERF_METRIC_NAMES = {
19
21
  restoreStateStoreRestore: "restoreState.storeRestore",
20
22
  generateTotal: "generate.total",
21
23
  generateReadResults: "generate.readResults",
24
+ generateReadResultsXcresultCheck: "generate.readResults.xcresultCheck",
25
+ generateReadResultsReaddir: "generate.readResults.readdir",
26
+ generateReadResultsFiles: "generate.readResults.files",
27
+ generateReadResultsRealpath: "generate.readResults.realpath",
28
+ generateReadResultsReaderRead: "generate.readResults.reader.read",
22
29
  generatePluginsDone: "generate.plugins.done",
30
+ storeVisitTestResultConvert: "store.visitTestResult.convert",
31
+ storeVisitTestResultDefaultLabels: "store.visitTestResult.defaultLabels",
32
+ storeVisitTestResultEnvironment: "store.visitTestResult.environment",
33
+ storeVisitTestResultRetry: "store.visitTestResult.retry",
34
+ storeVisitTestResultHistory: "store.visitTestResult.history",
35
+ storeVisitTestResultResolution: "store.visitTestResult.resolution",
36
+ storeVisitTestResultIndexes: "store.visitTestResult.indexes",
37
+ storeVisitAttachmentFileMetadata: "store.visitAttachmentFile.metadata",
23
38
  publishUploadTotal: "publish.upload.total",
24
39
  summaryGenerate: "summary.generate",
25
40
  };
26
41
  export const PERF_METRIC_PREFIXES = {
42
+ generatePlugin: "generate.plugin.",
27
43
  generatePluginDone: "generate.plugin.done.",
28
44
  publishUploadPlugin: "publish.upload.plugin.",
29
45
  };
30
- const getCoveredDurationSummary = () => {
31
- if (SPANS.length === 0) {
46
+ const getCoveredTiming = () => {
47
+ const timings = [
48
+ ...SPANS.map(({ startTimeMs, durationMs }) => ({
49
+ startTimeMs,
50
+ stopTimeMs: startTimeMs + durationMs,
51
+ })),
52
+ ...AGGREGATES.values(),
53
+ ...COUNTERS.values(),
54
+ ];
55
+ if (timings.length === 0) {
32
56
  return undefined;
33
57
  }
34
- const startTimeMs = Math.min(...SPANS.map(({ startTimeMs }) => startTimeMs));
35
- const endTimeMs = Math.max(...SPANS.map(({ startTimeMs, durationMs }) => startTimeMs + durationMs));
36
- const durationMs = round(endTimeMs - startTimeMs);
58
+ const startTimeMs = Math.min(...timings.map(({ startTimeMs }) => startTimeMs));
59
+ const stopTimeMs = Math.max(...timings.map(({ stopTimeMs }) => stopTimeMs));
37
60
  return {
38
- name: PERF_METRIC_NAMES.allureTotal,
39
- count: 1,
40
- totalMs: durationMs,
41
- minMs: durationMs,
42
- maxMs: durationMs,
43
- avgMs: durationMs,
61
+ startTimeMs,
62
+ stopTimeMs,
63
+ durationMs: round(stopTimeMs - startTimeMs),
44
64
  };
45
65
  };
46
66
  export const isPerfMetricsEnabled = () => ENABLED_VALUES.has((process.env.ALLURE_PERF_METRICS ?? "").toLowerCase());
@@ -91,8 +111,80 @@ export const measurePerf = async (name, fn) => {
91
111
  end();
92
112
  }
93
113
  };
114
+ const recordPerfTiming = (name, durationMs, startTimeMs) => {
115
+ if (!isPerfMetricsEnabled()) {
116
+ return;
117
+ }
118
+ const current = AGGREGATES.get(name);
119
+ if (!current) {
120
+ AGGREGATES.set(name, {
121
+ name,
122
+ count: 1,
123
+ totalMs: durationMs,
124
+ startTimeMs,
125
+ stopTimeMs: startTimeMs + durationMs,
126
+ });
127
+ return;
128
+ }
129
+ current.count += 1;
130
+ current.totalMs += durationMs;
131
+ current.startTimeMs = Math.min(current.startTimeMs, startTimeMs);
132
+ current.stopTimeMs = Math.max(current.stopTimeMs, startTimeMs + durationMs);
133
+ };
134
+ export const measurePerfAggregate = async (name, fn) => {
135
+ if (!isPerfMetricsEnabled()) {
136
+ return fn();
137
+ }
138
+ const startTimeMs = performance.now();
139
+ try {
140
+ return await fn();
141
+ }
142
+ finally {
143
+ recordPerfTiming(name, performance.now() - startTimeMs, startTimeMs);
144
+ }
145
+ };
146
+ export const measurePerfAggregateSync = (name, fn) => {
147
+ if (!isPerfMetricsEnabled()) {
148
+ return fn();
149
+ }
150
+ const startTimeMs = performance.now();
151
+ try {
152
+ return fn();
153
+ }
154
+ finally {
155
+ recordPerfTiming(name, performance.now() - startTimeMs, startTimeMs);
156
+ }
157
+ };
158
+ export const incrementPerfCounter = (name, value = 1, metadata) => {
159
+ if (!isPerfMetricsEnabled()) {
160
+ return;
161
+ }
162
+ const timeMs = performance.now();
163
+ const current = COUNTERS.get(name);
164
+ if (!current) {
165
+ COUNTERS.set(name, {
166
+ name,
167
+ value,
168
+ startTimeMs: timeMs,
169
+ stopTimeMs: timeMs,
170
+ ...(metadata ? { metadata } : {}),
171
+ });
172
+ return;
173
+ }
174
+ current.value += value;
175
+ current.stopTimeMs = timeMs;
176
+ current.metadata ?? (current.metadata = metadata);
177
+ };
178
+ const metricResult = (key, value, startTimeMs, stopTimeMs, metadata) => ({
179
+ id: randomUUID(),
180
+ key,
181
+ value: round(value),
182
+ start: round(performance.timeOrigin + startTimeMs),
183
+ stop: round(performance.timeOrigin + stopTimeMs),
184
+ ...metadata,
185
+ });
94
186
  export const getPerfMetricsResults = () => {
95
- const totalSummary = getCoveredDurationSummary();
187
+ const coveredTiming = getCoveredTiming();
96
188
  const results = SPANS.map((span) => ({
97
189
  id: randomUUID(),
98
190
  key: span.name,
@@ -100,15 +192,21 @@ export const getPerfMetricsResults = () => {
100
192
  start: round(performance.timeOrigin + span.startTimeMs),
101
193
  stop: round(performance.timeOrigin + span.startTimeMs + span.durationMs),
102
194
  }));
103
- if (totalSummary) {
195
+ if (coveredTiming) {
104
196
  results.unshift({
105
197
  id: randomUUID(),
106
198
  key: PERF_METRIC_NAMES.allureTotal,
107
- value: totalSummary.avgMs,
108
- start: round(performance.timeOrigin + Math.min(...SPANS.map(({ startTimeMs }) => startTimeMs))),
109
- stop: round(performance.timeOrigin + Math.max(...SPANS.map(({ startTimeMs, durationMs }) => startTimeMs + durationMs))),
199
+ value: coveredTiming.durationMs,
200
+ start: round(performance.timeOrigin + coveredTiming.startTimeMs),
201
+ stop: round(performance.timeOrigin + coveredTiming.stopTimeMs),
110
202
  });
111
203
  }
204
+ for (const aggregate of AGGREGATES.values()) {
205
+ results.push(metricResult(`${aggregate.name}.totalMs`, aggregate.totalMs, aggregate.startTimeMs, aggregate.stopTimeMs), metricResult(`${aggregate.name}.avgMs`, aggregate.totalMs / aggregate.count, aggregate.startTimeMs, aggregate.stopTimeMs));
206
+ }
207
+ for (const counter of COUNTERS.values()) {
208
+ results.push(metricResult(counter.name, counter.value, counter.startTimeMs, counter.stopTimeMs, counter.metadata));
209
+ }
112
210
  return results;
113
211
  };
114
212
  export const writePerfMetrics = async (output, fileName = PERF_METRICS_FILE) => {
@@ -123,6 +221,8 @@ export const writePerfMetrics = async (output, fileName = PERF_METRICS_FILE) =>
123
221
  };
124
222
  export const resetPerfMetrics = () => {
125
223
  SPANS.length = 0;
224
+ AGGREGATES.clear();
225
+ COUNTERS.clear();
126
226
  sequence = 0;
127
227
  for (const mark of MARKS) {
128
228
  performance.clearMarks(mark);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/core",
3
- "version": "3.19.0",
3
+ "version": "3.19.1",
4
4
  "description": "Collection of generic Allure utilities used across the entire project",
5
5
  "keywords": [
6
6
  "allure"
@@ -25,26 +25,26 @@
25
25
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
26
26
  },
27
27
  "dependencies": {
28
- "@allurereport/ci": "3.19.0",
29
- "@allurereport/cli-commons": "3.19.0",
30
- "@allurereport/core-api": "3.19.0",
31
- "@allurereport/plugin-agent": "3.19.0",
32
- "@allurereport/plugin-allure2": "3.19.0",
33
- "@allurereport/plugin-api": "3.19.0",
34
- "@allurereport/plugin-awesome": "3.19.0",
35
- "@allurereport/plugin-classic": "3.19.0",
36
- "@allurereport/plugin-csv": "3.19.0",
37
- "@allurereport/plugin-dashboard": "3.19.0",
38
- "@allurereport/plugin-jira": "3.19.0",
39
- "@allurereport/plugin-log": "3.19.0",
40
- "@allurereport/plugin-progress": "3.19.0",
41
- "@allurereport/plugin-slack": "3.19.0",
42
- "@allurereport/plugin-testops": "3.19.0",
43
- "@allurereport/plugin-testplan": "3.19.0",
44
- "@allurereport/reader": "3.19.0",
45
- "@allurereport/reader-api": "3.19.0",
46
- "@allurereport/service": "3.19.0",
47
- "@allurereport/summary": "3.19.0",
28
+ "@allurereport/ci": "3.19.1",
29
+ "@allurereport/cli-commons": "3.19.1",
30
+ "@allurereport/core-api": "3.19.1",
31
+ "@allurereport/plugin-agent": "3.19.1",
32
+ "@allurereport/plugin-allure2": "3.19.1",
33
+ "@allurereport/plugin-api": "3.19.1",
34
+ "@allurereport/plugin-awesome": "3.19.1",
35
+ "@allurereport/plugin-classic": "3.19.1",
36
+ "@allurereport/plugin-csv": "3.19.1",
37
+ "@allurereport/plugin-dashboard": "3.19.1",
38
+ "@allurereport/plugin-jira": "3.19.1",
39
+ "@allurereport/plugin-log": "3.19.1",
40
+ "@allurereport/plugin-progress": "3.19.1",
41
+ "@allurereport/plugin-slack": "3.19.1",
42
+ "@allurereport/plugin-testops": "3.19.1",
43
+ "@allurereport/plugin-testplan": "3.19.1",
44
+ "@allurereport/reader": "3.19.1",
45
+ "@allurereport/reader-api": "3.19.1",
46
+ "@allurereport/service": "3.19.1",
47
+ "@allurereport/summary": "3.19.1",
48
48
  "glob": "^13.0.6",
49
49
  "handlebars": "^4.7.9",
50
50
  "jiti": "^2.5.1",
@@ -58,7 +58,7 @@
58
58
  "@types/node": "^20",
59
59
  "@types/zip-stream": "^7.0.0",
60
60
  "@vitest/runner": "^2",
61
- "@vitest/snapshot": "^2.1.9",
61
+ "@vitest/snapshot": "^5.0.1",
62
62
  "allure-js-commons": "^3",
63
63
  "allure-vitest": "^3",
64
64
  "rimraf": "^6",