@allurereport/core 3.15.0 → 3.16.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/api.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { CategoriesConfig, KnownTestFailure, ResolvedAllureServiceConfig } from "@allurereport/core-api";
1
+ import type { CategoriesConfig, ResolvedAllureServiceConfig } from "@allurereport/core-api";
2
2
  import type { Plugin, ReportFiles, Config } from "@allurereport/plugin-api";
3
3
  import type { ResultsReader } from "@allurereport/reader-api";
4
4
  export interface PluginInstance {
@@ -8,18 +8,17 @@ export interface PluginInstance {
8
8
  options: Record<string, any>;
9
9
  }
10
10
  type FullConfigRequiredFromConfig = Required<Pick<Config, "name" | "output" | "open">>;
11
- export interface FullConfig extends Omit<Config, "name" | "output" | "open" | "allureService" | "knownIssuesPath" | "plugins" | "port">, FullConfigRequiredFromConfig {
11
+ export interface FullConfig extends Omit<Config, "name" | "output" | "open" | "allureService" | "plugins" | "port" | "resultsDir">, FullConfigRequiredFromConfig {
12
12
  port: Config["port"] | undefined;
13
13
  allowedEnvironments?: Config["allowedEnvironments"];
14
14
  reportFiles: ReportFiles;
15
15
  readers?: ResultsReader[];
16
16
  plugins?: PluginInstance[];
17
- known?: KnownTestFailure[];
18
- knownIssuesPath?: Config["knownIssuesPath"];
19
17
  realTime?: any;
20
18
  qualityGate?: Config["qualityGate"];
21
19
  allureService?: ResolvedAllureServiceConfig;
22
20
  categories?: CategoriesConfig;
23
21
  globalAttachments?: string[];
22
+ resultsDir?: string[];
24
23
  }
25
24
  export {};
package/dist/config.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface ConfigOverride {
9
9
  hideLabels?: Config["hideLabels"];
10
10
  historyPath?: Config["historyPath"];
11
11
  historyLimit?: Config["historyLimit"];
12
- knownIssuesPath?: Config["knownIssuesPath"];
12
+ resolutions?: Pick<NonNullable<Config["resolutions"]>, "knownIssuesPath">;
13
13
  plugins?: Config["plugins"];
14
14
  }
15
15
  export declare const parseIntegerConfigValue: (value: unknown, defaultValue: number, minValue: number) => number;
package/dist/config.js CHANGED
@@ -4,11 +4,12 @@ import * as process from "node:process";
4
4
  import { validateEnvironmentName } from "@allurereport/core-api";
5
5
  import { createJiti } from "jiti";
6
6
  import { parse } from "yaml";
7
- import { DEFAULT_KNOWN_ISSUES_PATH, hasKnownIssueRules, readKnownIssues, resolveExactIssuesFilePath } from "./known.js";
8
7
  import { FileSystemReportFiles } from "./plugin.js";
8
+ import { DEFAULT_KNOWN_ISSUES_PATH, resolveExactIssuesFilePath, validateResolutionsConfig } from "./resolutions.js";
9
9
  import { environmentIdentityById, environmentIdentityByName, validateAllowedEnvironmentIds, normalizeEnvironmentDescriptorMap, validateAllowedEnvironmentId, } from "./utils/environment.js";
10
10
  import { importWrapper } from "./utils/module.js";
11
11
  import { normalizeImportPath } from "./utils/path.js";
12
+ import { normalizeResultsDir } from "./utils/resultsDir.js";
12
13
  import { assertValidPluginIdForWindows, isWindows } from "./utils/windows.js";
13
14
  const CONFIG_FILENAMES = [
14
15
  "allurerc.js",
@@ -97,8 +98,7 @@ export const validateConfig = (config) => {
97
98
  "hideLabels",
98
99
  "historyPath",
99
100
  "historyLimit",
100
- "knownIssuesPath",
101
- "knownIssues",
101
+ "resolutions",
102
102
  "plugins",
103
103
  "defaultLabels",
104
104
  "variables",
@@ -110,6 +110,7 @@ export const validateConfig = (config) => {
110
110
  "allureService",
111
111
  "categories",
112
112
  "globalAttachments",
113
+ "resultsDir",
113
114
  ];
114
115
  const unsupportedFields = Object.keys(config).filter((key) => !supportedFields.includes(key));
115
116
  return {
@@ -193,6 +194,7 @@ export const resolveConfig = async (config, override = {}) => {
193
194
  if (!validationResult.valid) {
194
195
  throw new Error(`The provided Allure config contains unsupported fields: ${validationResult.fields.join(", ")}`);
195
196
  }
197
+ validateResolutionsConfig(config.resolutions);
196
198
  const { environments, environment, allowedEnvironments } = resolveConfigEnvironments(config);
197
199
  const name = override.name ?? config.name ?? "Allure Report";
198
200
  const open = override.open ?? config.open ?? false;
@@ -201,12 +203,15 @@ export const resolveConfig = async (config, override = {}) => {
201
203
  const historyPath = override.historyPath ?? config.historyPath;
202
204
  const historyLimit = override.historyLimit ?? config.historyLimit;
203
205
  const appendHistory = config.appendHistory ?? true;
204
- const configuredKnownIssuesPath = override.knownIssuesPath ?? config.knownIssuesPath;
205
- const knownIssuesPathInput = configuredKnownIssuesPath ?? (hasKnownIssueRules(config.knownIssues) ? DEFAULT_KNOWN_ISSUES_PATH : undefined);
206
+ const configuredKnownIssuesPath = override.resolutions?.knownIssuesPath ?? config.resolutions?.knownIssuesPath;
207
+ const knownIssuesPathInput = configuredKnownIssuesPath ?? (config.resolutions ? DEFAULT_KNOWN_ISSUES_PATH : undefined);
206
208
  const knownIssuesPath = await resolveExactIssuesFilePath(knownIssuesPathInput, "known issues");
209
+ const resolutions = config.resolutions || override.resolutions?.knownIssuesPath !== undefined
210
+ ? { ...(config.resolutions ?? { rules: [] }), knownIssuesPath }
211
+ : undefined;
207
212
  const output = resolve(override.output ?? config.output ?? "./allure-report");
208
- const known = knownIssuesPath ? await readKnownIssues(knownIssuesPath) : undefined;
209
213
  const variables = config.variables ?? {};
214
+ const resultsDir = normalizeResultsDir(config.resultsDir);
210
215
  let pluginInstances = [];
211
216
  const hasPluginsOverride = override.plugins !== undefined;
212
217
  if (!hasPluginsOverride || Object.keys(override.plugins ?? {}).length > 0) {
@@ -234,9 +239,7 @@ export const resolveConfig = async (config, override = {}) => {
234
239
  open,
235
240
  port,
236
241
  hideLabels,
237
- knownIssuesPath,
238
- known,
239
- knownIssues: config.knownIssues,
242
+ resolutions,
240
243
  environment,
241
244
  allowedEnvironments,
242
245
  variables,
@@ -259,6 +262,7 @@ export const resolveConfig = async (config, override = {}) => {
259
262
  : undefined,
260
263
  categories: config.categories,
261
264
  globalAttachments: config.globalAttachments,
265
+ ...(resultsDir.length ? { resultsDir } : {}),
262
266
  };
263
267
  };
264
268
  export const readConfig = async (cwd = process.cwd(), configPath, override) => {
package/dist/index.d.ts CHANGED
@@ -5,8 +5,9 @@ export * from "./utils/path.js";
5
5
  export * from "./utils/new.js";
6
6
  export * from "./utils/flaky.js";
7
7
  export * from "./utils/environment.js";
8
+ export * from "./utils/resultsDir.js";
8
9
  export * from "./history.js";
9
- export * from "./known.js";
10
+ export * from "./resolutions.js";
10
11
  export { resolveConfig, readConfig, readRawConfig, getPluginInstance } from "./config.js";
11
12
  export * from "./report.js";
12
13
  export * from "./plugin.js";
package/dist/index.js CHANGED
@@ -4,8 +4,9 @@ export * from "./utils/path.js";
4
4
  export * from "./utils/new.js";
5
5
  export * from "./utils/flaky.js";
6
6
  export * from "./utils/environment.js";
7
+ export * from "./utils/resultsDir.js";
7
8
  export * from "./history.js";
8
- export * from "./known.js";
9
+ export * from "./resolutions.js";
9
10
  export { resolveConfig, readConfig, readRawConfig, getPluginInstance } from "./config.js";
10
11
  export * from "./report.js";
11
12
  export * from "./plugin.js";
@@ -1,4 +1,4 @@
1
- import { type KnownTestFailure, type TestError, type TestResult } from "@allurereport/core-api";
1
+ import { type TestError, type TestResult } from "@allurereport/core-api";
2
2
  import type { QualityGateConfig, QualityGateValidationResult } from "@allurereport/plugin-api";
3
3
  export declare const stringifyQualityGateResults: (results: QualityGateValidationResult[]) => string;
4
4
  export declare const convertQualityGateResultsToTestErrors: (results: QualityGateValidationResult[]) => TestError[];
@@ -16,7 +16,6 @@ export declare class QualityGate {
16
16
  validate(payload: {
17
17
  state?: QualityGateState;
18
18
  trs: TestResult[];
19
- knownIssues: KnownTestFailure[];
20
19
  environment?: string;
21
20
  }): Promise<{
22
21
  fastFailed: boolean;
@@ -5,6 +5,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
5
5
  };
6
6
  var _QualityGateState_state, _QualityGateState_processedTestResultIds;
7
7
  import { gray, red } from "yoctocolors";
8
+ import { isIgnoredFailure } from "../resolutions.js";
8
9
  import { qualityGateDefaultRules } from "./rules.js";
9
10
  export const stringifyQualityGateResults = (results) => {
10
11
  if (results.length === 0) {
@@ -58,10 +59,10 @@ export class QualityGate {
58
59
  this.config = config;
59
60
  }
60
61
  async validate(payload) {
61
- const { state, trs, knownIssues, environment } = payload;
62
+ const { state, trs, environment } = payload;
62
63
  const trsToValidateById = new Map();
63
64
  for (const tr of trs) {
64
- if (tr.isRetry || state?.isTestResultProcessed(tr.id)) {
65
+ if (tr.isRetry || isIgnoredFailure(tr) || state?.isTestResultProcessed(tr.id)) {
65
66
  continue;
66
67
  }
67
68
  trsToValidateById.set(tr.id, tr);
@@ -97,7 +98,6 @@ export class QualityGate {
97
98
  setResult: (value, testResults) => state?.setResult?.(ruleId, value, testResults),
98
99
  },
99
100
  expected,
100
- knownIssues,
101
101
  environment,
102
102
  });
103
103
  if (result.success) {
@@ -3,7 +3,6 @@ export declare const maxFailuresRule: QualityGateRule<number>;
3
3
  export declare const minTestsCountRule: QualityGateRule<number>;
4
4
  export declare const successRateRule: QualityGateRule<number, {
5
5
  totalCount: number;
6
- unknownCount: number;
7
6
  passedCount: number;
8
7
  }>;
9
8
  export declare const maxDurationRule: QualityGateRule<number>;
@@ -11,6 +10,5 @@ export declare const allTestsContainEnvRule: QualityGateRule<string, number>;
11
10
  export declare const environmentsTestedRule: QualityGateRule<string[]>;
12
11
  export declare const qualityGateDefaultRules: (QualityGateRule<number> | QualityGateRule<number, {
13
12
  totalCount: number;
14
- unknownCount: number;
15
13
  passedCount: number;
16
14
  }> | QualityGateRule<string, number> | QualityGateRule<string[]>)[];
@@ -5,8 +5,7 @@ export const maxFailuresRule = {
5
5
  message: ({ actual, expected }) => `The number of failed tests ${bold(String(actual))} exceeds the allowed threshold value ${bold(String(expected))}`,
6
6
  validate: async ({ trs, expected, state }) => {
7
7
  const previous = state.getResult() ?? 0;
8
- const unknown = trs.filter((tr) => !tr.known);
9
- const failedTrs = unknown.filter(filterUnsuccessful);
8
+ const failedTrs = trs.filter(filterUnsuccessful);
10
9
  const testResults = failedTrs.map((tr) => tr.id);
11
10
  const actual = previous + failedTrs.length;
12
11
  state.setResult(actual, testResults);
@@ -34,16 +33,14 @@ export const successRateRule = {
34
33
  rule: "successRate",
35
34
  message: ({ actual, expected }) => `Success rate ${bold(String(actual))} is less, than expected ${bold(String(expected))}`,
36
35
  validate: async ({ trs, expected, state }) => {
37
- const previous = state.getResult() ?? { totalCount: 0, unknownCount: 0, passedCount: 0 };
38
- const unknown = trs.filter((tr) => !tr.known);
39
- const passedTrs = unknown.filter(filterSuccessful);
40
- const notPassedTrs = unknown.filter((tr) => !filterSuccessful(tr));
36
+ const previous = state.getResult() ?? { totalCount: 0, passedCount: 0 };
37
+ const passedTrs = trs.filter(filterSuccessful);
38
+ const notPassedTrs = trs.filter((tr) => !filterSuccessful(tr));
41
39
  const totalCount = previous.totalCount + trs.length;
42
- const unknownCount = previous.unknownCount + unknown.length;
43
40
  const passedCount = previous.passedCount + passedTrs.length;
44
41
  const testResults = notPassedTrs.map((tr) => tr.id);
45
- const rate = totalCount === 0 ? 0 : unknownCount === 0 ? 1 : passedCount / unknownCount;
46
- state.setResult({ totalCount, unknownCount, passedCount }, testResults);
42
+ const rate = totalCount === 0 ? 0 : passedCount / totalCount;
43
+ state.setResult({ totalCount, passedCount }, testResults);
47
44
  return {
48
45
  success: rate >= expected,
49
46
  actual: rate,
package/dist/report.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { KnownTestFailure, TestResult } from "@allurereport/core-api";
1
+ import type { TestResult } from "@allurereport/core-api";
2
2
  import { type ResultFile } from "@allurereport/plugin-api";
3
3
  import type { FullConfig } from "./api.js";
4
4
  import { type QualityGateState } from "./qualityGate/index.js";
@@ -19,7 +19,6 @@ export declare class AllureReport {
19
19
  readResult: (data: ResultFile) => Promise<void>;
20
20
  validate: (params: {
21
21
  trs: TestResult[];
22
- knownIssues: KnownTestFailure[];
23
22
  state?: QualityGateState;
24
23
  environment?: string;
25
24
  }) => Promise<{
package/dist/report.js CHANGED
@@ -31,9 +31,9 @@ import ZipReadStream from "node-stream-zip";
31
31
  import pLimit from "p-limit";
32
32
  import ZipWriteStream from "zip-stream";
33
33
  import { AllureLocalHistory, createHistory } from "./history.js";
34
- import { writeKnownIssues } from "./known.js";
35
34
  import { DefaultPluginState, PluginFiles } from "./plugin.js";
36
35
  import { QualityGate } from "./qualityGate/index.js";
36
+ import { writeKnownIssues } from "./resolutions.js";
37
37
  import { DefaultAllureStore } from "./store/store.js";
38
38
  import { environmentIdentityById, environmentIdentityByName } from "./utils/environment.js";
39
39
  import { measurePerf, PERF_METRIC_NAMES, PERF_METRIC_PREFIXES, startPerfSpan, writePerfMetrics } from "./utils/perf.js";
@@ -141,6 +141,7 @@ export class AllureReport {
141
141
  message: uploadProgressMessage,
142
142
  unitLabel: "files uploaded",
143
143
  prefix: "[AllureReport]",
144
+ silent: !!__classPrivateFieldGet(this, _AllureReport_realTime, "f"),
144
145
  });
145
146
  const endPublishPerfSpan = startPerfSpan(PERF_METRIC_NAMES.publishUploadTotal);
146
147
  const logUploadProgress = progressLogger.log;
@@ -282,12 +283,7 @@ export class AllureReport {
282
283
  }
283
284
  };
284
285
  this.validate = async (params) => {
285
- const { trs, knownIssues, state, environment } = params;
286
- const currentKnownIssues = await __classPrivateFieldGet(this, _AllureReport_store, "f").allKnownIssues();
287
- const effectiveKnownIssues = new Map();
288
- [...knownIssues, ...currentKnownIssues].forEach((issue) => {
289
- effectiveKnownIssues.set(issue.historyId, issue);
290
- });
286
+ const { trs, state, environment } = params;
291
287
  const qualityGateEnvironment = environment === undefined
292
288
  ? undefined
293
289
  : (environmentIdentityById(__classPrivateFieldGet(this, _AllureReport_environments, "f"), environment)?.name ??
@@ -295,7 +291,6 @@ export class AllureReport {
295
291
  environment);
296
292
  return __classPrivateFieldGet(this, _AllureReport_qualityGate, "f").validate({
297
293
  trs: trs.filter(Boolean),
298
- knownIssues: [...effectiveKnownIssues.values()],
299
294
  state,
300
295
  environment: qualityGateEnvironment,
301
296
  });
@@ -392,7 +387,7 @@ export class AllureReport {
392
387
  const addJsonDumpEntry = async (entryName, value) => {
393
388
  await addRequiredDumpEntry(Buffer.from(JSON.stringify(value)), entryName);
394
389
  };
395
- const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = {}, globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, knownIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], }) => [
390
+ const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = {}, globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexTestResultByResolutionIssue = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, resolutionIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], }) => [
396
391
  [AllureStoreDumpFiles.TestResults, testResults],
397
392
  [AllureStoreDumpFiles.TestCases, testCases],
398
393
  [AllureStoreDumpFiles.Fixtures, fixtures],
@@ -400,12 +395,13 @@ export class AllureReport {
400
395
  [AllureStoreDumpFiles.CheckResults, checkResults],
401
396
  [AllureStoreDumpFiles.Environments, environments],
402
397
  [AllureStoreDumpFiles.ReportVariables, reportVariables],
403
- [AllureStoreDumpFiles.KnownIssues, knownIssues],
398
+ [AllureStoreDumpFiles.ResolutionIssues, resolutionIssues],
404
399
  [AllureStoreDumpFiles.GlobalAttachments, globalAttachmentIds],
405
400
  [AllureStoreDumpFiles.GlobalErrors, globalErrors],
406
401
  [AllureStoreDumpFiles.IndexAttachmentsByTestResults, indexAttachmentByTestResult],
407
402
  [AllureStoreDumpFiles.IndexTestResultsByHistoryId, indexTestResultByHistoryId],
408
403
  [AllureStoreDumpFiles.IndexTestResultsByTestCase, indexTestResultByTestCase],
404
+ [AllureStoreDumpFiles.IndexTestResultsByResolutionIssue, indexTestResultByResolutionIssue],
409
405
  [AllureStoreDumpFiles.IndexAttachmentsByFixture, indexAttachmentByFixture],
410
406
  [AllureStoreDumpFiles.IndexFixturesByTestResult, indexFixturesByTestResult],
411
407
  [AllureStoreDumpFiles.QualityGateResults, qualityGateResults],
@@ -532,9 +528,10 @@ export class AllureReport {
532
528
  const indexAttachmentsEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByTestResults);
533
529
  const indexTestResultsByHistoryId = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByHistoryId);
534
530
  const indexTestResultsByTestCaseEntry = await requiredEntryData(AllureStoreDumpFiles.IndexTestResultsByTestCase);
531
+ const indexTestResultsByResolutionIssueEntry = await optionalEntryData(AllureStoreDumpFiles.IndexTestResultsByResolutionIssue);
535
532
  const indexAttachmentsByFixtureEntry = await requiredEntryData(AllureStoreDumpFiles.IndexAttachmentsByFixture);
536
533
  const indexFixturesByTestResultEntry = await requiredEntryData(AllureStoreDumpFiles.IndexFixturesByTestResult);
537
- const knownIssuesEntry = await requiredEntryData(AllureStoreDumpFiles.KnownIssues);
534
+ const resolutionIssuesEntry = await optionalEntryData(AllureStoreDumpFiles.ResolutionIssues);
538
535
  const qualityGateResultsEntry = await requiredEntryData(AllureStoreDumpFiles.QualityGateResults);
539
536
  const testResultIngestOrderEntry = await optionalEntryData(AllureStoreDumpFiles.TestResultIngestOrder);
540
537
  const attachmentsLinks = JSON.parse(attachmentsEntry.toString("utf8"));
@@ -547,12 +544,13 @@ export class AllureReport {
547
544
  case AllureStoreDumpFiles.Fixtures:
548
545
  case AllureStoreDumpFiles.Environments:
549
546
  case AllureStoreDumpFiles.ReportVariables:
550
- case AllureStoreDumpFiles.KnownIssues:
547
+ case AllureStoreDumpFiles.ResolutionIssues:
551
548
  case AllureStoreDumpFiles.GlobalAttachments:
552
549
  case AllureStoreDumpFiles.GlobalErrors:
553
550
  case AllureStoreDumpFiles.IndexAttachmentsByTestResults:
554
551
  case AllureStoreDumpFiles.IndexTestResultsByHistoryId:
555
552
  case AllureStoreDumpFiles.IndexTestResultsByTestCase:
553
+ case AllureStoreDumpFiles.IndexTestResultsByResolutionIssue:
556
554
  case AllureStoreDumpFiles.IndexAttachmentsByFixture:
557
555
  case AllureStoreDumpFiles.IndexFixturesByTestResult:
558
556
  case AllureStoreDumpFiles.QualityGateResults:
@@ -580,9 +578,12 @@ export class AllureReport {
580
578
  indexAttachmentByTestResult: JSON.parse(indexAttachmentsEntry.toString("utf8")),
581
579
  indexTestResultByHistoryId: JSON.parse(indexTestResultsByHistoryId.toString("utf8")),
582
580
  indexTestResultByTestCase: JSON.parse(indexTestResultsByTestCaseEntry.toString("utf8")),
581
+ indexTestResultByResolutionIssue: indexTestResultsByResolutionIssueEntry
582
+ ? JSON.parse(indexTestResultsByResolutionIssueEntry.toString("utf8"))
583
+ : {},
583
584
  indexAttachmentByFixture: JSON.parse(indexAttachmentsByFixtureEntry.toString("utf8")),
584
585
  indexFixturesByTestResult: JSON.parse(indexFixturesByTestResultEntry.toString("utf8")),
585
- knownIssues: JSON.parse(knownIssuesEntry.toString("utf8")),
586
+ resolutionIssues: resolutionIssuesEntry ? JSON.parse(resolutionIssuesEntry.toString("utf8")) : {},
586
587
  qualityGateResults: JSON.parse(qualityGateResultsEntry.toString("utf8")),
587
588
  testResultIdsIngestOrder: testResultIngestOrderEntry
588
589
  ? JSON.parse(testResultIngestOrderEntry.toString("utf8"))
@@ -892,7 +893,7 @@ export class AllureReport {
892
893
  }
893
894
  }
894
895
  });
895
- const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], known, knownIssues, knownIssuesPath, reportFiles, realTime, historyPath, historyLimit, appendHistory, defaultLabels = {}, variables = {}, environment, allowedEnvironments, environments, output, hideLabels, qualityGate, dump, categories, allureService, globalAttachments, } = opts;
896
+ const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], resolutions, reportFiles, realTime, historyPath, historyLimit, appendHistory, defaultLabels = {}, variables = {}, environment, allowedEnvironments, environments, output, hideLabels, qualityGate, dump, categories, allureService, globalAttachments, } = opts;
896
897
  const allureServiceAccessToken = allureService?.accessToken;
897
898
  if (allureServiceAccessToken) {
898
899
  const allureServiceClientConfig = {
@@ -917,7 +918,7 @@ export class AllureReport {
917
918
  __classPrivateFieldSet(this, _AllureReport_environments, environments ?? {}, "f");
918
919
  __classPrivateFieldSet(this, _AllureReport_globalAttachments, globalAttachments, "f");
919
920
  __classPrivateFieldSet(this, _AllureReport_appendHistory, appendHistory ?? true, "f");
920
- __classPrivateFieldSet(this, _AllureReport_knownIssuesPath, knownIssuesPath, "f");
921
+ __classPrivateFieldSet(this, _AllureReport_knownIssuesPath, resolutions?.knownIssuesPath, "f");
921
922
  if (qualityGate) {
922
923
  __classPrivateFieldSet(this, _AllureReport_qualityGate, new QualityGate(qualityGate), "f");
923
924
  }
@@ -941,8 +942,7 @@ export class AllureReport {
941
942
  reportVariables: variables,
942
943
  environmentsConfig: environments,
943
944
  history: __classPrivateFieldGet(this, _AllureReport_history, "f"),
944
- known,
945
- knownIssuesConfig: knownIssues,
945
+ resolutionsConfig: resolutions,
946
946
  defaultLabels,
947
947
  environment,
948
948
  allowedEnvironments,
@@ -0,0 +1,8 @@
1
+ import type { ResolutionRule, ResolutionsConfig, TestResult } from "@allurereport/core-api";
2
+ import type { AllureStore } from "@allurereport/plugin-api";
3
+ export declare const DEFAULT_KNOWN_ISSUES_PATH = "known-issues.json";
4
+ export declare const validateResolutionsConfig: (config?: ResolutionsConfig) => void;
5
+ export declare const getResolutionByRules: (testResult: TestResult, config?: ResolutionsConfig) => ResolutionRule | undefined;
6
+ export declare const isIgnoredFailure: (testResult: TestResult) => boolean;
7
+ export declare const resolveExactIssuesFilePath: (pathOrDir: string | undefined, label: string) => Promise<string | undefined>;
8
+ export declare const writeKnownIssues: (store: AllureStore, knownIssuesPath?: string) => Promise<void>;
@@ -0,0 +1,181 @@
1
+ import { mkdir, stat, writeFile } from "node:fs/promises";
2
+ import { dirname, extname, resolve } from "node:path";
3
+ import { isFileNotFoundError } from "./utils/misc.js";
4
+ export const DEFAULT_KNOWN_ISSUES_PATH = "known-issues.json";
5
+ const nonEmpty = (value) => typeof value === "string" && value.trim().length > 0;
6
+ const validateStringList = (value, path, errors) => {
7
+ if (value === undefined) {
8
+ return;
9
+ }
10
+ if (!Array.isArray(value) || value.length === 0 || value.some((entry) => !nonEmpty(entry))) {
11
+ errors.push(`${path} must be a non-empty array of non-empty strings`);
12
+ }
13
+ };
14
+ const placeholderCount = (value) => (typeof value === "string" ? (value.match(/%s/g)?.length ?? 0) : 0);
15
+ const validateLinkTemplate = (type, template, errors) => {
16
+ if (!nonEmpty(type)) {
17
+ errors.push("resolutions.links keys must be non-empty strings");
18
+ }
19
+ if (!nonEmpty(template?.urlTemplate) || placeholderCount(template.urlTemplate) !== 1) {
20
+ errors.push(`resolutions.links.${type}.urlTemplate must contain exactly one %s`);
21
+ }
22
+ if (template?.nameTemplate === undefined) {
23
+ return;
24
+ }
25
+ if (!nonEmpty(template.nameTemplate) || placeholderCount(template.nameTemplate) !== 1) {
26
+ errors.push(`resolutions.links.${type}.nameTemplate must contain exactly one %s`);
27
+ }
28
+ };
29
+ const validateMessageRegexp = (value, path, errors) => {
30
+ if (value === undefined) {
31
+ return;
32
+ }
33
+ try {
34
+ new RegExp(value);
35
+ }
36
+ catch {
37
+ errors.push(`${path}.messageRegexp must be a valid regular expression`);
38
+ }
39
+ };
40
+ const validateMatcher = (matcher, path, errors) => {
41
+ validateStringList(matcher.testCaseId, `${path}.testCaseId`, errors);
42
+ validateStringList(matcher.retryHash, `${path}.retryHash`, errors);
43
+ validateStringList(matcher.environment, `${path}.environment`, errors);
44
+ if (![matcher.messageRegexp, matcher.testCaseId, matcher.retryHash, matcher.environment].some((value) => value !== undefined)) {
45
+ errors.push(`${path} must contain at least one matcher`);
46
+ }
47
+ validateMessageRegexp(matcher.messageRegexp, path, errors);
48
+ };
49
+ const validateIssueUrl = (rule, template, errors) => {
50
+ if (!nonEmpty(template.urlTemplate) || placeholderCount(template.urlTemplate) !== 1) {
51
+ return;
52
+ }
53
+ let url;
54
+ try {
55
+ url = new URL(template.urlTemplate.replace("%s", encodeURIComponent(rule.issue.id)));
56
+ }
57
+ catch {
58
+ errors.push(`resolutions.links.${rule.issue.type}.urlTemplate must resolve to an absolute URL`);
59
+ return;
60
+ }
61
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
62
+ errors.push(`resolutions.links.${rule.issue.type}.urlTemplate must resolve to an HTTP(S) URL`);
63
+ }
64
+ };
65
+ const validateIssueRule = (rule, path, config, issueIds, errors) => {
66
+ if (!nonEmpty(rule.issue?.id) || !nonEmpty(rule.issue?.type)) {
67
+ errors.push(`${path}.issue.id and ${path}.issue.type must be non-empty strings`);
68
+ return;
69
+ }
70
+ if (issueIds.has(rule.issue.id)) {
71
+ errors.push(`${path}.issue.id must be unique`);
72
+ }
73
+ issueIds.add(rule.issue.id);
74
+ const template = config.links?.[rule.issue.type];
75
+ if (!template) {
76
+ errors.push(`${path}.issue.type must reference resolutions.links`);
77
+ return;
78
+ }
79
+ validateIssueUrl(rule, template, errors);
80
+ };
81
+ const validateIgnoredRule = (rule, path, errors) => {
82
+ if (!nonEmpty(rule.comment)) {
83
+ errors.push(`${path}.comment must be a non-empty string`);
84
+ }
85
+ };
86
+ export const validateResolutionsConfig = (config) => {
87
+ if (!config) {
88
+ return;
89
+ }
90
+ const errors = [];
91
+ if (!Array.isArray(config.rules)) {
92
+ throw new Error("The provided resolutions config is invalid: resolutions.rules must be an array");
93
+ }
94
+ for (const [type, template] of Object.entries(config.links ?? {})) {
95
+ validateLinkTemplate(type, template, errors);
96
+ }
97
+ const issueIds = new Set();
98
+ config.rules.forEach((rule, index) => {
99
+ const path = `resolutions.rules[${index}]`;
100
+ const matcher = rule;
101
+ validateMatcher(matcher, path, errors);
102
+ if (matcher.resolution === "issue") {
103
+ validateIssueRule(matcher, path, config, issueIds, errors);
104
+ return;
105
+ }
106
+ if (matcher.resolution === "muted" || matcher.resolution === "accepted") {
107
+ validateIgnoredRule(matcher, path, errors);
108
+ return;
109
+ }
110
+ errors.push(`${path}.resolution must be issue, muted, or accepted`);
111
+ });
112
+ if (errors.length > 0) {
113
+ throw new Error(`The provided resolutions config is invalid: ${errors.join("; ")}`);
114
+ }
115
+ };
116
+ const matches = (rule, testResult) => {
117
+ const { id, allureId, externalId } = testResult.testCase ?? {};
118
+ const testCaseIds = [id, allureId, externalId].filter((value) => typeof value === "string");
119
+ return ((!rule.messageRegexp || new RegExp(rule.messageRegexp).test(testResult.error?.message ?? "")) &&
120
+ (!rule.testCaseId || rule.testCaseId.some((id) => testCaseIds.includes(id))) &&
121
+ (!rule.retryHash || (!!testResult.retryHash && rule.retryHash.includes(testResult.retryHash))) &&
122
+ (!rule.environment || (!!testResult.environment && rule.environment.includes(testResult.environment))));
123
+ };
124
+ export const getResolutionByRules = (testResult, config) => {
125
+ if ((testResult.status !== "failed" && testResult.status !== "broken") || !config?.rules.length) {
126
+ return undefined;
127
+ }
128
+ for (const resolution of ["issue", "muted", "accepted"]) {
129
+ const rule = config.rules.find((candidate) => candidate.resolution === resolution && matches(candidate, testResult));
130
+ if (rule) {
131
+ return rule;
132
+ }
133
+ }
134
+ return undefined;
135
+ };
136
+ export const isIgnoredFailure = (testResult) => testResult.resolution === "muted" || testResult.resolution === "accepted";
137
+ export const resolveExactIssuesFilePath = async (pathOrDir, label) => {
138
+ if (!pathOrDir)
139
+ return undefined;
140
+ const path = resolve(pathOrDir);
141
+ if (extname(path).toLowerCase() !== ".json") {
142
+ throw new Error(`Invalid ${label} path ${JSON.stringify(pathOrDir)}: expected exact .json file path`);
143
+ }
144
+ try {
145
+ if ((await stat(path)).isDirectory()) {
146
+ throw new Error(`Invalid ${label} path ${JSON.stringify(pathOrDir)}: expected file, got directory`);
147
+ }
148
+ }
149
+ catch (e) {
150
+ if (!isFileNotFoundError(e))
151
+ throw e;
152
+ }
153
+ return path;
154
+ };
155
+ export const writeKnownIssues = async (store, knownIssuesPath) => {
156
+ const path = await resolveExactIssuesFilePath(knownIssuesPath, "known issues");
157
+ if (!path)
158
+ return;
159
+ const records = new Map();
160
+ for (const testResult of await store.allTestResults()) {
161
+ if (testResult.resolution !== "issue" || testResult.isRetry || !testResult.retryHash) {
162
+ continue;
163
+ }
164
+ const issue = await store.resolutionIssueByTestResultId(testResult.id);
165
+ if (!issue || (testResult.status !== "failed" && testResult.status !== "broken")) {
166
+ continue;
167
+ }
168
+ const record = records.get(issue.id) ?? { ...issue, testResults: {} };
169
+ record.testResults[testResult.retryHash] = {
170
+ name: testResult.name,
171
+ fullName: testResult.fullName,
172
+ environment: testResult.environment,
173
+ status: testResult.status,
174
+ error: testResult.error,
175
+ };
176
+ records.set(issue.id, record);
177
+ }
178
+ const file = { resolutionIssues: [...records.values()].sort((a, b) => a.id.localeCompare(b.id)) };
179
+ await mkdir(dirname(path), { recursive: true });
180
+ await writeFile(path, `${JSON.stringify(file)}\n`, "utf-8");
181
+ };
@@ -53,7 +53,6 @@ export const testResultRawToState = (stateData, raw, context) => {
53
53
  expectedResultHtml: raw.expectedResultHtml,
54
54
  flaky: raw.flaky ?? false,
55
55
  muted: raw.muted ?? false,
56
- known: raw.known ?? false,
57
56
  isRetry: false,
58
57
  labels,
59
58
  steps: convertSteps(stateData, raw.steps).convertedSteps,
@@ -1,11 +1,10 @@
1
- import { type AllureCheckResult, type AllureHistory, type AttachmentLink, type DefaultLabelsConfig, type EnvironmentIdentity, type EnvironmentsConfig, type GlobalAttachmentLink, type HistoryDataPoint, type HistoryTestResult, type KnownIssuesConfig, type KnownTestFailure, 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 AttachmentLink, type DefaultLabelsConfig, type EnvironmentIdentity, type EnvironmentsConfig, type GlobalAttachmentLink, type HistoryDataPoint, type HistoryTestResult, type ResolutionIssue, type ResolutionsConfig, 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>;
5
5
  export declare const updateMapWithRecord: <K extends string | number | symbol, T = any>(map: Map<K, T>, record: Record<K, T>) => Map<K, T>;
6
6
  export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
7
7
  #private;
8
- readonly known: Map<string, KnownTestFailure>;
9
8
  readonly indexTestResultByTestCase: Map<string, TestResult[]>;
10
9
  readonly indexTestResultByEnvironmentId: Map<string, TestResult[]>;
11
10
  readonly indexTestResultByHistoryId: Map<string, TestResult[]>;
@@ -14,8 +13,7 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
14
13
  readonly indexFixturesByTestResult: Map<string, TestFixtureResult[]>;
15
14
  constructor(params?: {
16
15
  history?: AllureHistory;
17
- known?: KnownTestFailure[];
18
- knownIssuesConfig?: KnownIssuesConfig;
16
+ resolutionsConfig?: ResolutionsConfig;
19
17
  realtimeDispatcher?: RealtimeEventsDispatcher;
20
18
  realtimeSubscriber?: RealtimeSubscriber;
21
19
  defaultLabels?: DefaultLabelsConfig;
@@ -56,7 +54,9 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
56
54
  allHistoryDataPoints(): Promise<HistoryDataPoint[]>;
57
55
  allHistoryDataPointsByEnvironment(environment: string): Promise<HistoryDataPoint[]>;
58
56
  allHistoryDataPointsByEnvironmentId(environmentId: string): Promise<HistoryDataPoint[]>;
59
- allKnownIssues(): Promise<KnownTestFailure[]>;
57
+ allResolutionIssues(): Promise<ResolutionIssue[]>;
58
+ resolutionIssueByTestResultId(trId: string): Promise<ResolutionIssue | undefined>;
59
+ testResultsByResolutionIssueId(resolutionIssueId: string): Promise<TestResult[]>;
60
60
  allNewTestResults(filter?: TestResultFilter, history?: HistoryDataPoint[]): Promise<TestResult[]>;
61
61
  testCaseById(tcId: string): Promise<TestCase | undefined>;
62
62
  testResultById(trId: string): Promise<TestResult | undefined>;
@@ -9,11 +9,11 @@ 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 _DefaultAllureStore_instances, _DefaultAllureStore_testResults, _DefaultAllureStore_environmentDisplayNames, _DefaultAllureStore_environmentNameToId, _DefaultAllureStore_attachments, _DefaultAllureStore_attachmentContents, _DefaultAllureStore_testCases, _DefaultAllureStore_metadata, _DefaultAllureStore_history, _DefaultAllureStore_knownIssuesConfig, _DefaultAllureStore_fixtures, _DefaultAllureStore_defaultLabels, _DefaultAllureStore_environment, _DefaultAllureStore_environmentsConfig, _DefaultAllureStore_reportVariables, _DefaultAllureStore_realtimeDispatcher, _DefaultAllureStore_realtimeSubscriber, _DefaultAllureStore_allowedEnvironmentIds, _DefaultAllureStore_retrySubstore, _DefaultAllureStore_testResultIdsByEnvironmentId, _DefaultAllureStore_cachedEnvironmentEntries, _DefaultAllureStore_globalAttachmentIds, _DefaultAllureStore_globalAttachmentIdsByEnv, _DefaultAllureStore_globalErrors, _DefaultAllureStore_globalErrorsByEnv, _DefaultAllureStore_globalExitCode, _DefaultAllureStore_checkResultsById, _DefaultAllureStore_qualityGateResults, _DefaultAllureStore_historyPoints, _DefaultAllureStore_environments, _DefaultAllureStore_historyIdMatches, _DefaultAllureStore_mergeEnvironmentIdentity, _DefaultAllureStore_environmentIdForLookup, _DefaultAllureStore_addEnvironments, _DefaultAllureStore_environmentIdByName, _DefaultAllureStore_setTestResultEnvironmentId, _DefaultAllureStore_assertAllowedEnvironmentId, _DefaultAllureStore_assertAllowedStoredEnvironment, _DefaultAllureStore_environmentIdByTestResult, _DefaultAllureStore_assignRetryHash, _DefaultAllureStore_setKnownIssue, _DefaultAllureStore_classifyKnownIssue, _DefaultAllureStore_rebuildRetrySubstore, _DefaultAllureStore_resolveGlobalEnvironmentIdentity, _DefaultAllureStore_globalAttachmentId, _DefaultAllureStore_indexGlobalError, _DefaultAllureStore_addGlobalError, _DefaultAllureStore_indexGlobalAttachment, _DefaultAllureStore_addGlobalAttachment, _DefaultAllureStore_restoreAttachmentContent, _DefaultAllureStore_relinkRestoredAttachmentSteps, _DefaultAllureStore_retriesByTr, _DefaultAllureStore_historyByTr;
12
+ var _DefaultAllureStore_instances, _DefaultAllureStore_testResults, _DefaultAllureStore_environmentDisplayNames, _DefaultAllureStore_environmentNameToId, _DefaultAllureStore_attachments, _DefaultAllureStore_attachmentContents, _DefaultAllureStore_testCases, _DefaultAllureStore_metadata, _DefaultAllureStore_history, _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_cachedEnvironmentEntries, _DefaultAllureStore_globalAttachmentIds, _DefaultAllureStore_globalAttachmentIdsByEnv, _DefaultAllureStore_globalErrors, _DefaultAllureStore_globalErrorsByEnv, _DefaultAllureStore_globalExitCode, _DefaultAllureStore_checkResultsById, _DefaultAllureStore_qualityGateResults, _DefaultAllureStore_historyPoints, _DefaultAllureStore_environments, _DefaultAllureStore_mergeEnvironmentIdentity, _DefaultAllureStore_environmentIdForLookup, _DefaultAllureStore_addEnvironments, _DefaultAllureStore_environmentIdByName, _DefaultAllureStore_setTestResultEnvironmentId, _DefaultAllureStore_assertAllowedEnvironmentId, _DefaultAllureStore_assertAllowedStoredEnvironment, _DefaultAllureStore_environmentIdByTestResult, _DefaultAllureStore_assignRetryHash, _DefaultAllureStore_classifyResolution, _DefaultAllureStore_associateResolutionIssue, _DefaultAllureStore_removeResolutionIssueAssociation, _DefaultAllureStore_rebuildRetrySubstore, _DefaultAllureStore_resolveGlobalEnvironmentIdentity, _DefaultAllureStore_globalAttachmentId, _DefaultAllureStore_indexGlobalError, _DefaultAllureStore_addGlobalError, _DefaultAllureStore_indexGlobalAttachment, _DefaultAllureStore_addGlobalAttachment, _DefaultAllureStore_restoreAttachmentContent, _DefaultAllureStore_relinkRestoredAttachmentSteps, _DefaultAllureStore_retriesByTr, _DefaultAllureStore_historyByTr;
13
13
  import { extname } from "node:path";
14
14
  import { DEFAULT_ENVIRONMENT, DEFAULT_ENVIRONMENT_IDENTITY, compareBy, createDictionary, getHistoryIdCandidates, getWorstStatus, normalizeHistoryDataPoint, ordinal, reverse, selectHistoryTestResults, validateEnvironmentId, validateEnvironmentName, } from "@allurereport/core-api";
15
15
  import { md5, } from "@allurereport/plugin-api";
16
- import { getKnownIssueByRules } from "../known.js";
16
+ import { getResolutionByRules, isIgnoredFailure } from "../resolutions.js";
17
17
  import { environmentIdentityById, normalizeEnvironmentDescriptorMap, resolveEnvironmentIdentity, resolveStoredEnvironmentIdentity, validateAllowedEnvironmentId, } from "../utils/environment.js";
18
18
  import { isFlaky } from "../utils/flaky.js";
19
19
  import { getStatusTransition } from "../utils/new.js";
@@ -64,8 +64,10 @@ export class DefaultAllureStore {
64
64
  _DefaultAllureStore_testCases.set(this, void 0);
65
65
  _DefaultAllureStore_metadata.set(this, void 0);
66
66
  _DefaultAllureStore_history.set(this, void 0);
67
- _DefaultAllureStore_knownIssuesConfig.set(this, void 0);
68
- this.known = new Map();
67
+ _DefaultAllureStore_resolutionsConfig.set(this, void 0);
68
+ _DefaultAllureStore_resolutionIssues.set(this, new Map());
69
+ _DefaultAllureStore_testResultIdsByResolutionIssueId.set(this, new Map());
70
+ _DefaultAllureStore_resolutionIssueIdByTestResultId.set(this, new Map());
69
71
  _DefaultAllureStore_fixtures.set(this, void 0);
70
72
  _DefaultAllureStore_defaultLabels.set(this, {});
71
73
  _DefaultAllureStore_environment.set(this, void 0);
@@ -92,7 +94,7 @@ export class DefaultAllureStore {
92
94
  _DefaultAllureStore_qualityGateResults.set(this, []);
93
95
  _DefaultAllureStore_historyPoints.set(this, []);
94
96
  _DefaultAllureStore_environments.set(this, []);
95
- const { history, known = [], knownIssuesConfig, realtimeDispatcher, realtimeSubscriber, defaultLabels = {}, environment, allowedEnvironments, environmentsConfig = {}, reportVariables = {}, } = params ?? {};
97
+ const { history, resolutionsConfig, realtimeDispatcher, realtimeSubscriber, defaultLabels = {}, environment, allowedEnvironments, environmentsConfig = {}, reportVariables = {}, } = params ?? {};
96
98
  const errors = [];
97
99
  const { normalized: normalizedEnvironmentsConfig, identities, errors: configErrors, } = normalizeEnvironmentDescriptorMap(environmentsConfig, "environmentsConfig");
98
100
  errors.push(...configErrors);
@@ -117,8 +119,7 @@ export class DefaultAllureStore {
117
119
  __classPrivateFieldSet(this, _DefaultAllureStore_metadata, new Map(), "f");
118
120
  __classPrivateFieldSet(this, _DefaultAllureStore_fixtures, new Map(), "f");
119
121
  __classPrivateFieldSet(this, _DefaultAllureStore_history, history, "f");
120
- __classPrivateFieldSet(this, _DefaultAllureStore_knownIssuesConfig, knownIssuesConfig, "f");
121
- known.forEach((ktf) => this.known.set(ktf.historyId, ktf));
122
+ __classPrivateFieldSet(this, _DefaultAllureStore_resolutionsConfig, resolutionsConfig, "f");
122
123
  __classPrivateFieldSet(this, _DefaultAllureStore_realtimeDispatcher, realtimeDispatcher, "f");
123
124
  __classPrivateFieldSet(this, _DefaultAllureStore_realtimeSubscriber, realtimeSubscriber, "f");
124
125
  __classPrivateFieldSet(this, _DefaultAllureStore_defaultLabels, defaultLabels, "f");
@@ -330,7 +331,7 @@ export class DefaultAllureStore {
330
331
  testResult.transition = getStatusTransition(testResult, trHistory);
331
332
  testResult.flaky = isFlaky(testResult, trHistory);
332
333
  }
333
- testResult.known = __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_classifyKnownIssue).call(this, testResult, environmentIdentity.id);
334
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_classifyResolution).call(this, testResult);
334
335
  __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").set(testResult.id, testResult);
335
336
  __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_setTestResultEnvironmentId).call(this, testResult, environmentIdentity.id);
336
337
  __classPrivateFieldGet(this, _DefaultAllureStore_retrySubstore, "f").recordIngestOrder(testResult.id);
@@ -512,8 +513,21 @@ export class DefaultAllureStore {
512
513
  return result;
513
514
  }, []);
514
515
  }
515
- async allKnownIssues() {
516
- return [...this.known.values()].flat();
516
+ async allResolutionIssues() {
517
+ return [...__classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f").values()];
518
+ }
519
+ async resolutionIssueByTestResultId(trId) {
520
+ const issueId = __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssueIdByTestResultId, "f").get(trId);
521
+ return issueId ? __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f").get(issueId) : undefined;
522
+ }
523
+ async testResultsByResolutionIssueId(resolutionIssueId) {
524
+ const testResultIds = __classPrivateFieldGet(this, _DefaultAllureStore_testResultIdsByResolutionIssueId, "f").get(resolutionIssueId);
525
+ if (!testResultIds) {
526
+ return [];
527
+ }
528
+ return [...testResultIds]
529
+ .map((testResultId) => __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").get(testResultId))
530
+ .filter(Boolean);
517
531
  }
518
532
  async allNewTestResults(filter, history) {
519
533
  if (!__classPrivateFieldGet(this, _DefaultAllureStore_history, "f") && !history) {
@@ -631,7 +645,7 @@ export class DefaultAllureStore {
631
645
  }
632
646
  async blockingFailedTestResults() {
633
647
  const failedTestResults = await this.failedTestResults();
634
- return failedTestResults.filter((tr) => !tr.known);
648
+ return failedTestResults.filter((tr) => !isIgnoredFailure(tr));
635
649
  }
636
650
  async unknownFailedTestResults() {
637
651
  return this.blockingFailedTestResults();
@@ -792,9 +806,10 @@ export class DefaultAllureStore {
792
806
  indexAttachmentByTestResult: {},
793
807
  indexTestResultByHistoryId: {},
794
808
  indexTestResultByTestCase: {},
809
+ indexTestResultByResolutionIssue: {},
795
810
  indexAttachmentByFixture: {},
796
811
  indexFixturesByTestResult: {},
797
- knownIssues: {},
812
+ resolutionIssues: mapToObject(__classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f")),
798
813
  qualityGateResults: __classPrivateFieldGet(this, _DefaultAllureStore_qualityGateResults, "f"),
799
814
  testResultIdsIngestOrder: __classPrivateFieldGet(this, _DefaultAllureStore_retrySubstore, "f").ingestOrderIdsForDump(),
800
815
  };
@@ -810,16 +825,16 @@ export class DefaultAllureStore {
810
825
  this.indexTestResultByTestCase.forEach((trs, tcId) => {
811
826
  storeDump.indexTestResultByTestCase[tcId] = trs.map((tr) => tr.id);
812
827
  });
828
+ __classPrivateFieldGet(this, _DefaultAllureStore_testResultIdsByResolutionIssueId, "f").forEach((trIds, resolutionIssueId) => {
829
+ storeDump.indexTestResultByResolutionIssue[resolutionIssueId] = [...trIds];
830
+ });
813
831
  this.indexFixturesByTestResult.forEach((fixtures, trId) => {
814
832
  storeDump.indexFixturesByTestResult[trId] = fixtures.map((f) => f.id);
815
833
  });
816
- this.known.forEach((known, historyId) => {
817
- storeDump.knownIssues[historyId] = known;
818
- });
819
834
  return storeDump;
820
835
  }
821
836
  async restoreState(stateDump, attachmentsContents = {}) {
822
- const { testResults, attachments, testCases, fixtures, reportVariables, environments, globalAttachmentIds = [], globalErrors = [], checkResults, indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, knownIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], } = stateDump;
837
+ const { testResults, attachments, testCases, fixtures, reportVariables, environments, globalAttachmentIds = [], globalErrors = [], checkResults, indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexTestResultByResolutionIssue = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, resolutionIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], } = stateDump;
823
838
  const storedEnvironmentAliases = environments.flatMap((environmentValue) => {
824
839
  if (typeof environmentValue === "string") {
825
840
  return [{ id: environmentValue, name: environmentValue }];
@@ -869,7 +884,7 @@ export class DefaultAllureStore {
869
884
  envNameToId.set(id, id);
870
885
  }
871
886
  Object.values(testResults).forEach((testResult) => {
872
- testResult.known ?? (testResult.known = false);
887
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_removeResolutionIssueAssociation).call(this, testResult.id);
873
888
  __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").set(testResult.id, testResult);
874
889
  const storedEnvKey = typeof testResult.environment === "string" ? testResult.environment : undefined;
875
890
  const envId = (storedEnvKey ? envNameToId.get(storedEnvKey) : undefined) ?? __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_environmentIdByTestResult).call(this, testResult);
@@ -885,7 +900,18 @@ export class DefaultAllureStore {
885
900
  updateMapWithRecord(__classPrivateFieldGet(this, _DefaultAllureStore_attachments, "f"), attachments);
886
901
  updateMapWithRecord(__classPrivateFieldGet(this, _DefaultAllureStore_testCases, "f"), testCases);
887
902
  updateMapWithRecord(__classPrivateFieldGet(this, _DefaultAllureStore_fixtures, "f"), fixtures);
888
- updateMapWithRecord(this.known, knownIssues);
903
+ updateMapWithRecord(__classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f"), resolutionIssues);
904
+ Object.entries(indexTestResultByResolutionIssue).forEach(([resolutionIssueId, testResultIds]) => {
905
+ const resolutionIssue = __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f").get(resolutionIssueId);
906
+ if (!resolutionIssue) {
907
+ return;
908
+ }
909
+ testResultIds.forEach((testResultId) => {
910
+ if (__classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").has(testResultId)) {
911
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_associateResolutionIssue).call(this, resolutionIssue, testResultId);
912
+ }
913
+ });
914
+ });
889
915
  Object.entries(attachmentsContents).forEach(([id, content]) => {
890
916
  __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_restoreAttachmentContent).call(this, id, content);
891
917
  });
@@ -975,8 +1001,13 @@ export class DefaultAllureStore {
975
1001
  existingFixtures.push(...fxs);
976
1002
  });
977
1003
  __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_rebuildRetrySubstore).call(this);
978
- for (const testResult of __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").values()) {
979
- testResult.known = __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_classifyKnownIssue).call(this, testResult, __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_environmentIdByTestResult).call(this, testResult));
1004
+ if (__classPrivateFieldGet(this, _DefaultAllureStore_resolutionsConfig, "f")) {
1005
+ __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f").clear();
1006
+ __classPrivateFieldGet(this, _DefaultAllureStore_testResultIdsByResolutionIssueId, "f").clear();
1007
+ __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssueIdByTestResultId, "f").clear();
1008
+ for (const testResult of __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").values()) {
1009
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_classifyResolution).call(this, testResult);
1010
+ }
980
1011
  }
981
1012
  qualityGateResults.forEach((result, index) => {
982
1013
  __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_assertAllowedStoredEnvironment).call(this, {
@@ -989,9 +1020,7 @@ export class DefaultAllureStore {
989
1020
  });
990
1021
  }
991
1022
  }
992
- _DefaultAllureStore_testResults = new WeakMap(), _DefaultAllureStore_environmentDisplayNames = new WeakMap(), _DefaultAllureStore_environmentNameToId = new WeakMap(), _DefaultAllureStore_attachments = new WeakMap(), _DefaultAllureStore_attachmentContents = new WeakMap(), _DefaultAllureStore_testCases = new WeakMap(), _DefaultAllureStore_metadata = new WeakMap(), _DefaultAllureStore_history = new WeakMap(), _DefaultAllureStore_knownIssuesConfig = new WeakMap(), _DefaultAllureStore_fixtures = new WeakMap(), _DefaultAllureStore_defaultLabels = new WeakMap(), _DefaultAllureStore_environment = new WeakMap(), _DefaultAllureStore_environmentsConfig = new WeakMap(), _DefaultAllureStore_reportVariables = new WeakMap(), _DefaultAllureStore_realtimeDispatcher = new WeakMap(), _DefaultAllureStore_realtimeSubscriber = new WeakMap(), _DefaultAllureStore_allowedEnvironmentIds = new WeakMap(), _DefaultAllureStore_retrySubstore = new WeakMap(), _DefaultAllureStore_testResultIdsByEnvironmentId = new WeakMap(), _DefaultAllureStore_cachedEnvironmentEntries = new WeakMap(), _DefaultAllureStore_globalAttachmentIds = new WeakMap(), _DefaultAllureStore_globalAttachmentIdsByEnv = new WeakMap(), _DefaultAllureStore_globalErrors = new WeakMap(), _DefaultAllureStore_globalErrorsByEnv = new WeakMap(), _DefaultAllureStore_globalExitCode = new WeakMap(), _DefaultAllureStore_checkResultsById = new WeakMap(), _DefaultAllureStore_qualityGateResults = new WeakMap(), _DefaultAllureStore_historyPoints = new WeakMap(), _DefaultAllureStore_environments = new WeakMap(), _DefaultAllureStore_instances = new WeakSet(), _DefaultAllureStore_historyIdMatches = function _DefaultAllureStore_historyIdMatches(historyIdCandidates, indexByHistoryId) {
993
- return historyIdCandidates.find((historyId) => indexByHistoryId.has(historyId));
994
- }, _DefaultAllureStore_mergeEnvironmentIdentity = function _DefaultAllureStore_mergeEnvironmentIdentity(existingEnvironment, incomingEnvironment) {
1023
+ _DefaultAllureStore_testResults = new WeakMap(), _DefaultAllureStore_environmentDisplayNames = new WeakMap(), _DefaultAllureStore_environmentNameToId = new WeakMap(), _DefaultAllureStore_attachments = new WeakMap(), _DefaultAllureStore_attachmentContents = new WeakMap(), _DefaultAllureStore_testCases = new WeakMap(), _DefaultAllureStore_metadata = new WeakMap(), _DefaultAllureStore_history = new WeakMap(), _DefaultAllureStore_resolutionsConfig = new WeakMap(), _DefaultAllureStore_resolutionIssues = new WeakMap(), _DefaultAllureStore_testResultIdsByResolutionIssueId = new WeakMap(), _DefaultAllureStore_resolutionIssueIdByTestResultId = new WeakMap(), _DefaultAllureStore_fixtures = new WeakMap(), _DefaultAllureStore_defaultLabels = new WeakMap(), _DefaultAllureStore_environment = new WeakMap(), _DefaultAllureStore_environmentsConfig = new WeakMap(), _DefaultAllureStore_reportVariables = new WeakMap(), _DefaultAllureStore_realtimeDispatcher = new WeakMap(), _DefaultAllureStore_realtimeSubscriber = new WeakMap(), _DefaultAllureStore_allowedEnvironmentIds = new WeakMap(), _DefaultAllureStore_retrySubstore = new WeakMap(), _DefaultAllureStore_testResultIdsByEnvironmentId = new WeakMap(), _DefaultAllureStore_cachedEnvironmentEntries = new WeakMap(), _DefaultAllureStore_globalAttachmentIds = new WeakMap(), _DefaultAllureStore_globalAttachmentIdsByEnv = new WeakMap(), _DefaultAllureStore_globalErrors = new WeakMap(), _DefaultAllureStore_globalErrorsByEnv = new WeakMap(), _DefaultAllureStore_globalExitCode = new WeakMap(), _DefaultAllureStore_checkResultsById = new WeakMap(), _DefaultAllureStore_qualityGateResults = new WeakMap(), _DefaultAllureStore_historyPoints = new WeakMap(), _DefaultAllureStore_environments = new WeakMap(), _DefaultAllureStore_instances = new WeakSet(), _DefaultAllureStore_mergeEnvironmentIdentity = function _DefaultAllureStore_mergeEnvironmentIdentity(existingEnvironment, incomingEnvironment) {
995
1024
  const configuredEnvironment = environmentIdentityById(__classPrivateFieldGet(this, _DefaultAllureStore_environmentsConfig, "f"), incomingEnvironment.id);
996
1025
  if (configuredEnvironment) {
997
1026
  return configuredEnvironment;
@@ -1093,23 +1122,35 @@ _DefaultAllureStore_testResults = new WeakMap(), _DefaultAllureStore_environment
1093
1122
  const environmentId = options?.environmentId ?? __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_environmentIdByTestResult).call(this, testResult);
1094
1123
  const parametersHash = options?.parametersHash ?? calculateParametersHash(testResult.parameters);
1095
1124
  testResult.retryHash = calculateRetryHash(testResult.testCase?.id, parametersHash, environmentId);
1096
- }, _DefaultAllureStore_setKnownIssue = function _DefaultAllureStore_setKnownIssue(knownIssue) {
1097
- this.known.set(knownIssue.historyId, knownIssue);
1098
- }, _DefaultAllureStore_classifyKnownIssue = function _DefaultAllureStore_classifyKnownIssue(testResult, environmentId) {
1099
- if (testResult.status !== "failed" && testResult.status !== "broken") {
1100
- return false;
1125
+ }, _DefaultAllureStore_classifyResolution = function _DefaultAllureStore_classifyResolution(testResult) {
1126
+ const rule = getResolutionByRules(testResult, __classPrivateFieldGet(this, _DefaultAllureStore_resolutionsConfig, "f"));
1127
+ testResult.resolution = rule?.resolution;
1128
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_removeResolutionIssueAssociation).call(this, testResult.id);
1129
+ if (rule?.resolution !== "issue") {
1130
+ return;
1101
1131
  }
1102
- const historyIdCandidates = getHistoryIdCandidates(testResult);
1103
- if (historyIdCandidates.length === 0) {
1104
- return false;
1132
+ const resolutionIssue = { ...rule.issue, comment: rule.comment };
1133
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_associateResolutionIssue).call(this, resolutionIssue, testResult.id);
1134
+ }, _DefaultAllureStore_associateResolutionIssue = function _DefaultAllureStore_associateResolutionIssue(resolutionIssue, testResultId) {
1135
+ __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_removeResolutionIssueAssociation).call(this, testResultId);
1136
+ __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f").set(resolutionIssue.id, resolutionIssue);
1137
+ const testResultIds = __classPrivateFieldGet(this, _DefaultAllureStore_testResultIdsByResolutionIssueId, "f").get(resolutionIssue.id) ?? new Set();
1138
+ testResultIds.add(testResultId);
1139
+ __classPrivateFieldGet(this, _DefaultAllureStore_testResultIdsByResolutionIssueId, "f").set(resolutionIssue.id, testResultIds);
1140
+ __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssueIdByTestResultId, "f").set(testResultId, resolutionIssue.id);
1141
+ }, _DefaultAllureStore_removeResolutionIssueAssociation = function _DefaultAllureStore_removeResolutionIssueAssociation(testResultId) {
1142
+ const resolutionIssueId = __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssueIdByTestResultId, "f").get(testResultId);
1143
+ if (!resolutionIssueId) {
1144
+ return;
1105
1145
  }
1106
- const ruleKnownIssue = getKnownIssueByRules(testResult, __classPrivateFieldGet(this, _DefaultAllureStore_knownIssuesConfig, "f"), environmentId);
1107
- if (ruleKnownIssue) {
1108
- __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_setKnownIssue).call(this, ruleKnownIssue);
1109
- return true;
1146
+ __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssueIdByTestResultId, "f").delete(testResultId);
1147
+ const testResultIds = __classPrivateFieldGet(this, _DefaultAllureStore_testResultIdsByResolutionIssueId, "f").get(resolutionIssueId);
1148
+ testResultIds?.delete(testResultId);
1149
+ if (testResultIds?.size) {
1150
+ return;
1110
1151
  }
1111
- const knownHistoryId = __classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_historyIdMatches).call(this, historyIdCandidates, this.known);
1112
- return !!knownHistoryId;
1152
+ __classPrivateFieldGet(this, _DefaultAllureStore_testResultIdsByResolutionIssueId, "f").delete(resolutionIssueId);
1153
+ __classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f").delete(resolutionIssueId);
1113
1154
  }, _DefaultAllureStore_rebuildRetrySubstore = function _DefaultAllureStore_rebuildRetrySubstore() {
1114
1155
  __classPrivateFieldGet(this, _DefaultAllureStore_retrySubstore, "f").reset();
1115
1156
  for (const [, testResult] of __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f")) {
@@ -0,0 +1 @@
1
+ export declare const normalizeResultsDir: (value?: string | string[]) => string[];
@@ -0,0 +1,7 @@
1
+ export const normalizeResultsDir = (value) => {
2
+ if (value === undefined) {
3
+ return [];
4
+ }
5
+ const values = Array.isArray(value) ? value : [value];
6
+ return values.filter((entry) => entry.length > 0);
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/core",
3
- "version": "3.15.0",
3
+ "version": "3.16.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.15.0",
29
- "@allurereport/cli-commons": "3.15.0",
30
- "@allurereport/core-api": "3.15.0",
31
- "@allurereport/plugin-agent": "3.15.0",
32
- "@allurereport/plugin-allure2": "3.15.0",
33
- "@allurereport/plugin-api": "3.15.0",
34
- "@allurereport/plugin-awesome": "3.15.0",
35
- "@allurereport/plugin-classic": "3.15.0",
36
- "@allurereport/plugin-csv": "3.15.0",
37
- "@allurereport/plugin-dashboard": "3.15.0",
38
- "@allurereport/plugin-jira": "3.15.0",
39
- "@allurereport/plugin-log": "3.15.0",
40
- "@allurereport/plugin-progress": "3.15.0",
41
- "@allurereport/plugin-slack": "3.15.0",
42
- "@allurereport/plugin-testops": "3.15.0",
43
- "@allurereport/plugin-testplan": "3.15.0",
44
- "@allurereport/reader": "3.15.0",
45
- "@allurereport/reader-api": "3.15.0",
46
- "@allurereport/service": "3.15.0",
47
- "@allurereport/summary": "3.15.0",
28
+ "@allurereport/ci": "3.16.1",
29
+ "@allurereport/cli-commons": "3.16.1",
30
+ "@allurereport/core-api": "3.16.1",
31
+ "@allurereport/plugin-agent": "3.16.1",
32
+ "@allurereport/plugin-allure2": "3.16.1",
33
+ "@allurereport/plugin-api": "3.16.1",
34
+ "@allurereport/plugin-awesome": "3.16.1",
35
+ "@allurereport/plugin-classic": "3.16.1",
36
+ "@allurereport/plugin-csv": "3.16.1",
37
+ "@allurereport/plugin-dashboard": "3.16.1",
38
+ "@allurereport/plugin-jira": "3.16.1",
39
+ "@allurereport/plugin-log": "3.16.1",
40
+ "@allurereport/plugin-progress": "3.16.1",
41
+ "@allurereport/plugin-slack": "3.16.1",
42
+ "@allurereport/plugin-testops": "3.16.1",
43
+ "@allurereport/plugin-testplan": "3.16.1",
44
+ "@allurereport/reader": "3.16.1",
45
+ "@allurereport/reader-api": "3.16.1",
46
+ "@allurereport/service": "3.16.1",
47
+ "@allurereport/summary": "3.16.1",
48
48
  "glob": "^13.0.6",
49
49
  "handlebars": "^4.7.9",
50
50
  "jiti": "^2.5.1",
package/dist/known.d.ts DELETED
@@ -1,8 +0,0 @@
1
- import type { KnownIssuesConfig, KnownTestFailure, TestResult } from "@allurereport/core-api";
2
- import type { AllureStore } from "@allurereport/plugin-api";
3
- export declare const DEFAULT_KNOWN_ISSUES_PATH = "known-issues.json";
4
- export declare const hasKnownIssueRules: (knownIssues?: KnownIssuesConfig) => boolean;
5
- export declare const getKnownIssueByRules: (testResult: TestResult, knownIssues: KnownIssuesConfig | undefined, environmentId?: string) => KnownTestFailure | undefined;
6
- export declare const resolveExactIssuesFilePath: (pathOrDir: string | undefined, label: string) => Promise<string | undefined>;
7
- export declare const readKnownIssues: (knownIssuePath: string) => Promise<KnownTestFailure[]>;
8
- export declare const writeKnownIssues: (store: AllureStore, knownIssuesPath?: string) => Promise<void>;
package/dist/known.js DELETED
@@ -1,86 +0,0 @@
1
- import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
2
- import { dirname, extname, resolve } from "node:path";
3
- import { isFileNotFoundError } from "./utils/misc.js";
4
- export const DEFAULT_KNOWN_ISSUES_PATH = "known-issues.json";
5
- export const hasKnownIssueRules = (knownIssues) => (knownIssues?.rules?.length ?? 0) > 0;
6
- const messageMatches = (rule, testResult) => {
7
- if (!rule.messageRegexp) {
8
- return true;
9
- }
10
- const message = testResult.error?.message;
11
- return typeof message === "string" && new RegExp(rule.messageRegexp).test(message);
12
- };
13
- const testCaseIdMatches = (rule, testResult) => {
14
- const { id, allureId, externalId } = testResult.testCase ?? {};
15
- return !rule.testCaseId || [id, allureId, externalId].includes(rule.testCaseId);
16
- };
17
- const retryHashMatches = (rule, testResult) => {
18
- return !rule.retryHash || rule.retryHash === testResult.retryHash;
19
- };
20
- const environmentMatches = (rule, testResult) => {
21
- return !rule.environmentId || rule.environmentId === testResult.environment;
22
- };
23
- export const getKnownIssueByRules = (testResult, knownIssues, environmentId) => {
24
- if (!testResult.historyId || !hasKnownIssueRules(knownIssues)) {
25
- return undefined;
26
- }
27
- const matchedRule = knownIssues.rules.find((rule) => [messageMatches, testCaseIdMatches, environmentMatches, retryHashMatches].every((matcher) => matcher(rule, testResult)));
28
- if (!matchedRule) {
29
- return undefined;
30
- }
31
- return {
32
- historyId: testResult.historyId,
33
- reason: matchedRule.decision.reason,
34
- links: matchedRule.decision.links,
35
- error: testResult.error,
36
- };
37
- };
38
- export const resolveExactIssuesFilePath = async (pathOrDir, label) => {
39
- if (!pathOrDir) {
40
- return undefined;
41
- }
42
- const path = resolve(pathOrDir);
43
- if (extname(path).toLowerCase() !== ".json") {
44
- throw new Error(`Invalid ${label} path ${JSON.stringify(pathOrDir)}: expected exact .json file path`);
45
- }
46
- try {
47
- const pathStats = await stat(path);
48
- if (pathStats.isDirectory()) {
49
- throw new Error(`Invalid ${label} path ${JSON.stringify(pathOrDir)}: expected file, got directory`);
50
- }
51
- }
52
- catch (e) {
53
- if (!isFileNotFoundError(e)) {
54
- throw e;
55
- }
56
- }
57
- return path;
58
- };
59
- export const readKnownIssues = async (knownIssuePath) => {
60
- const path = await resolveExactIssuesFilePath(knownIssuePath, "known issues");
61
- if (!path) {
62
- return [];
63
- }
64
- try {
65
- const content = await readFile(path, { encoding: "utf-8" });
66
- return JSON.parse(content);
67
- }
68
- catch (e) {
69
- if (isFileNotFoundError(e)) {
70
- return [];
71
- }
72
- throw e;
73
- }
74
- };
75
- const writeKnownIssueRecords = async (knownIssues, knownIssuesPath) => {
76
- const path = await resolveExactIssuesFilePath(knownIssuesPath, "known issues");
77
- if (!path) {
78
- return;
79
- }
80
- await mkdir(dirname(path), { recursive: true });
81
- await writeFile(path, `${JSON.stringify(knownIssues)}\n`, "utf-8");
82
- };
83
- export const writeKnownIssues = async (store, knownIssuesPath) => {
84
- const knownIssues = await store.allKnownIssues();
85
- await writeKnownIssueRecords(knownIssues, knownIssuesPath);
86
- };