@allurereport/core 3.16.1 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +3 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +5 -1
- package/dist/history.d.ts +2 -2
- package/dist/history.js +12 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/qualityGate/qualityGate.d.ts +6 -4
- package/dist/qualityGate/qualityGate.js +3 -1
- package/dist/qualityGate/rules.d.ts +13 -8
- package/dist/qualityGate/rules.js +137 -7
- package/dist/report.js +111 -37
- package/dist/store/store.d.ts +4 -1
- package/dist/store/store.js +36 -5
- package/dist/utils/artifacts.d.ts +14 -0
- package/dist/utils/artifacts.js +35 -0
- package/dist/utils/perf.d.ts +6 -10
- package/dist/utils/perf.js +41 -28
- package/package.json +21 -21
package/dist/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CategoriesConfig, ResolvedAllureServiceConfig } from "@allurereport/core-api";
|
|
1
|
+
import type { CategoriesConfig, PerformanceConfig, 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 {
|
|
@@ -16,9 +16,11 @@ export interface FullConfig extends Omit<Config, "name" | "output" | "open" | "a
|
|
|
16
16
|
plugins?: PluginInstance[];
|
|
17
17
|
realTime?: any;
|
|
18
18
|
qualityGate?: Config["qualityGate"];
|
|
19
|
+
performance?: PerformanceConfig;
|
|
19
20
|
allureService?: ResolvedAllureServiceConfig;
|
|
20
21
|
categories?: CategoriesConfig;
|
|
21
22
|
globalAttachments?: string[];
|
|
23
|
+
cwd?: string;
|
|
22
24
|
resultsDir?: string[];
|
|
23
25
|
}
|
|
24
26
|
export {};
|
package/dist/config.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Config, Plugin, PluginConstructorContext, PluginDescriptor } from
|
|
|
2
2
|
import type { FullConfig, PluginInstance } from "./api.js";
|
|
3
3
|
type PluginConstructor = new (options?: Record<string, any>, context?: PluginConstructorContext) => Plugin;
|
|
4
4
|
export interface ConfigOverride {
|
|
5
|
+
cwd?: string;
|
|
5
6
|
name?: Config["name"];
|
|
6
7
|
output?: Config["output"];
|
|
7
8
|
open?: Config["open"];
|
package/dist/config.js
CHANGED
|
@@ -107,6 +107,7 @@ export const validateConfig = (config) => {
|
|
|
107
107
|
"environments",
|
|
108
108
|
"appendHistory",
|
|
109
109
|
"qualityGate",
|
|
110
|
+
"performance",
|
|
110
111
|
"allureService",
|
|
111
112
|
"categories",
|
|
112
113
|
"globalAttachments",
|
|
@@ -210,6 +211,7 @@ export const resolveConfig = async (config, override = {}) => {
|
|
|
210
211
|
? { ...(config.resolutions ?? { rules: [] }), knownIssuesPath }
|
|
211
212
|
: undefined;
|
|
212
213
|
const output = resolve(override.output ?? config.output ?? "./allure-report");
|
|
214
|
+
const cwd = resolve(override.cwd ?? process.cwd());
|
|
213
215
|
const variables = config.variables ?? {};
|
|
214
216
|
const resultsDir = normalizeResultsDir(config.resultsDir);
|
|
215
217
|
let pluginInstances = [];
|
|
@@ -235,6 +237,7 @@ export const resolveConfig = async (config, override = {}) => {
|
|
|
235
237
|
}
|
|
236
238
|
return {
|
|
237
239
|
name,
|
|
240
|
+
cwd,
|
|
238
241
|
output,
|
|
239
242
|
open,
|
|
240
243
|
port,
|
|
@@ -251,6 +254,7 @@ export const resolveConfig = async (config, override = {}) => {
|
|
|
251
254
|
plugins: pluginInstances,
|
|
252
255
|
defaultLabels: config.defaultLabels ?? {},
|
|
253
256
|
qualityGate: config.qualityGate,
|
|
257
|
+
performance: config.performance,
|
|
254
258
|
allureService: config.allureService
|
|
255
259
|
? {
|
|
256
260
|
accessToken: config.allureService.accessToken,
|
|
@@ -289,7 +293,7 @@ export const readConfig = async (cwd = process.cwd(), configPath, override) => {
|
|
|
289
293
|
default:
|
|
290
294
|
config = DEFAULT_CONFIG;
|
|
291
295
|
}
|
|
292
|
-
const fullConfig = await resolveConfig(config, override);
|
|
296
|
+
const fullConfig = await resolveConfig(config, { ...override, cwd });
|
|
293
297
|
return fullConfig;
|
|
294
298
|
};
|
|
295
299
|
export const readRawConfig = async (cwd = process.cwd(), configPath) => {
|
package/dist/history.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type AllureHistory, type HistoryDataPoint, type TestCase, type TestResult } from "@allurereport/core-api";
|
|
2
|
-
export declare const createHistory: (reportUuid: string, reportName: string | undefined, testCases: TestCase[], testResults: TestResult[], remoteUrl?: string) => HistoryDataPoint;
|
|
1
|
+
import { type AllureHistory, type HistoryDataPoint, type MetricSample, type TestCase, type TestResult } from "@allurereport/core-api";
|
|
2
|
+
export declare const createHistory: (reportUuid: string, reportName: string | undefined, testCases: TestCase[], testResults: TestResult[], remoteUrl?: string, metrics?: MetricSample[]) => HistoryDataPoint;
|
|
3
3
|
export declare class AllureLocalHistory implements AllureHistory {
|
|
4
4
|
#private;
|
|
5
5
|
private readonly params;
|
package/dist/history.js
CHANGED
|
@@ -43,7 +43,17 @@ const createHistoryItems = (testResults, remoteUrl) => {
|
|
|
43
43
|
return acc;
|
|
44
44
|
}, {});
|
|
45
45
|
};
|
|
46
|
-
|
|
46
|
+
const metricsToHistoryValues = (metrics) => {
|
|
47
|
+
const grouped = new Map();
|
|
48
|
+
for (const metric of metrics) {
|
|
49
|
+
if (!metric.key || !Number.isFinite(metric.value)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
grouped.set(metric.key, [...(grouped.get(metric.key) ?? []), metric.value]);
|
|
53
|
+
}
|
|
54
|
+
return Object.fromEntries([...grouped.entries()].map(([key, values]) => [key, values.reduce((acc, value) => acc + value, 0) / values.length]));
|
|
55
|
+
};
|
|
56
|
+
export const createHistory = (reportUuid, reportName = "Allure Report", testCases, testResults, remoteUrl = "", metrics = []) => {
|
|
47
57
|
const knownTestCaseIds = testCases.map((tc) => tc.id);
|
|
48
58
|
return {
|
|
49
59
|
uuid: reportUuid,
|
|
@@ -51,7 +61,7 @@ export const createHistory = (reportUuid, reportName = "Allure Report", testCase
|
|
|
51
61
|
timestamp: new Date().getTime(),
|
|
52
62
|
knownTestCaseIds,
|
|
53
63
|
testResults: createHistoryItems(testResults, remoteUrl),
|
|
54
|
-
metrics:
|
|
64
|
+
metrics: metricsToHistoryValues(metrics),
|
|
55
65
|
url: remoteUrl,
|
|
56
66
|
};
|
|
57
67
|
};
|
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, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
|
|
14
|
+
export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, metricMaxRule, metricMinRule, metricMaxDeltaRule, metricMaxDeltaPercentRule, convertQualityGateResultsToTestErrors, 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, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
|
|
13
|
+
export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, metricMaxRule, metricMinRule, metricMaxDeltaRule, metricMaxDeltaPercentRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { type TestError, type TestResult } from "@allurereport/core-api";
|
|
2
|
-
import type { QualityGateConfig, QualityGateValidationResult } from "@allurereport/plugin-api";
|
|
1
|
+
import { type MetricSample, type TestError, type TestResult } from "@allurereport/core-api";
|
|
2
|
+
import type { QualityGateConfig, QualityGateMetricHistoryPoint, QualityGateValidationResult } from "@allurereport/plugin-api";
|
|
3
3
|
export declare const stringifyQualityGateResults: (results: QualityGateValidationResult[]) => string;
|
|
4
4
|
export declare const convertQualityGateResultsToTestErrors: (results: QualityGateValidationResult[]) => TestError[];
|
|
5
5
|
export declare class QualityGateState {
|
|
6
6
|
#private;
|
|
7
|
-
setResult(rule: string, value:
|
|
8
|
-
getResult(rule: string):
|
|
7
|
+
setResult(rule: string, value: unknown, testResults?: string[]): void;
|
|
8
|
+
getResult(rule: string): unknown;
|
|
9
9
|
getTestResults(rule: string): string[];
|
|
10
10
|
markTestResultsProcessed(testResults: TestResult[]): void;
|
|
11
11
|
isTestResultProcessed(trId: string): boolean;
|
|
@@ -16,6 +16,8 @@ export declare class QualityGate {
|
|
|
16
16
|
validate(payload: {
|
|
17
17
|
state?: QualityGateState;
|
|
18
18
|
trs: TestResult[];
|
|
19
|
+
metrics?: MetricSample[];
|
|
20
|
+
previousHistory?: QualityGateMetricHistoryPoint[];
|
|
19
21
|
environment?: string;
|
|
20
22
|
}): Promise<{
|
|
21
23
|
fastFailed: boolean;
|
|
@@ -59,7 +59,7 @@ export class QualityGate {
|
|
|
59
59
|
this.config = config;
|
|
60
60
|
}
|
|
61
61
|
async validate(payload) {
|
|
62
|
-
const { state, trs, environment } = payload;
|
|
62
|
+
const { state, trs, metrics = [], previousHistory = [], environment } = payload;
|
|
63
63
|
const trsToValidateById = new Map();
|
|
64
64
|
for (const tr of trs) {
|
|
65
65
|
if (tr.isRetry || isIgnoredFailure(tr) || state?.isTestResultProcessed(tr.id)) {
|
|
@@ -98,6 +98,8 @@ export class QualityGate {
|
|
|
98
98
|
setResult: (value, testResults) => state?.setResult?.(ruleId, value, testResults),
|
|
99
99
|
},
|
|
100
100
|
expected,
|
|
101
|
+
metrics,
|
|
102
|
+
previousHistory,
|
|
101
103
|
environment,
|
|
102
104
|
});
|
|
103
105
|
if (result.success) {
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { type QualityGateRule } from "@allurereport/plugin-api";
|
|
2
|
+
type MetricRuleConfig = {
|
|
3
|
+
key: string;
|
|
4
|
+
value: number;
|
|
5
|
+
title?: string;
|
|
6
|
+
unit?: string;
|
|
7
|
+
};
|
|
2
8
|
export declare const maxFailuresRule: QualityGateRule<number>;
|
|
3
9
|
export declare const minTestsCountRule: QualityGateRule<number>;
|
|
4
|
-
export declare const successRateRule: QualityGateRule<number
|
|
5
|
-
totalCount: number;
|
|
6
|
-
passedCount: number;
|
|
7
|
-
}>;
|
|
10
|
+
export declare const successRateRule: QualityGateRule<number>;
|
|
8
11
|
export declare const maxDurationRule: QualityGateRule<number>;
|
|
9
12
|
export declare const allTestsContainEnvRule: QualityGateRule<string, number>;
|
|
10
13
|
export declare const environmentsTestedRule: QualityGateRule<string[]>;
|
|
11
|
-
export declare const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
export declare const metricMaxRule: QualityGateRule<MetricRuleConfig>;
|
|
15
|
+
export declare const metricMinRule: QualityGateRule<MetricRuleConfig>;
|
|
16
|
+
export declare const metricMaxDeltaRule: QualityGateRule<MetricRuleConfig>;
|
|
17
|
+
export declare const metricMaxDeltaPercentRule: QualityGateRule<MetricRuleConfig>;
|
|
18
|
+
export declare const qualityGateDefaultRules: (QualityGateRule<number> | QualityGateRule<string, number> | QualityGateRule<string[]> | QualityGateRule<MetricRuleConfig>)[];
|
|
19
|
+
export {};
|
|
@@ -1,10 +1,80 @@
|
|
|
1
1
|
import { filterSuccessful, filterUnsuccessful } from "@allurereport/core-api";
|
|
2
2
|
import { bold } from "yoctocolors";
|
|
3
|
+
const numberStateValue = (value) => (Number.isFinite(value) ? Number(value) : 0);
|
|
4
|
+
const stringArrayStateValue = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
5
|
+
const successRateStateValue = (value) => {
|
|
6
|
+
if (typeof value !== "object" || value === null) {
|
|
7
|
+
return { totalCount: 0, passedCount: 0 };
|
|
8
|
+
}
|
|
9
|
+
const state = value;
|
|
10
|
+
return {
|
|
11
|
+
totalCount: numberStateValue(state.totalCount),
|
|
12
|
+
passedCount: numberStateValue(state.passedCount),
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
const metricValues = (metrics, key) => metrics
|
|
16
|
+
.map((metric) => (metric.key === key ? metric.value : undefined))
|
|
17
|
+
.filter((value) => Number.isFinite(value));
|
|
18
|
+
const metricAverage = (metrics, key) => {
|
|
19
|
+
const values = metricValues(metrics, key);
|
|
20
|
+
if (values.length === 0) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return values.reduce((acc, value) => acc + value, 0) / values.length;
|
|
24
|
+
};
|
|
25
|
+
const previousMetricValue = (history, key) => {
|
|
26
|
+
const previousHistory = [...history].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
27
|
+
for (const historyPoint of previousHistory) {
|
|
28
|
+
const value = historyPoint.metrics?.[key];
|
|
29
|
+
if (Number.isFinite(value)) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
};
|
|
35
|
+
const metricActual = (metrics, key, value) => {
|
|
36
|
+
const sample = metrics.find((metric) => metric.key === key);
|
|
37
|
+
return {
|
|
38
|
+
key,
|
|
39
|
+
value,
|
|
40
|
+
...(sample?.title ? { title: sample.title } : {}),
|
|
41
|
+
...(sample?.unit ? { unit: sample.unit } : {}),
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const formatMetricValue = (value, unit) => {
|
|
45
|
+
if (!Number.isFinite(value)) {
|
|
46
|
+
return "n/a";
|
|
47
|
+
}
|
|
48
|
+
const finiteValue = value;
|
|
49
|
+
const formatted = Number.isInteger(finiteValue) ? String(finiteValue) : String(Number(finiteValue.toFixed(3)));
|
|
50
|
+
return unit ? `${formatted} ${unit}` : formatted;
|
|
51
|
+
};
|
|
52
|
+
const metricRuleTitle = (actual) => actual.title ?? actual.key;
|
|
53
|
+
const metricRuleUnit = (actual, expected) => actual.unit ?? expected.unit;
|
|
54
|
+
const missingMetricResult = (actual) => ({
|
|
55
|
+
success: false,
|
|
56
|
+
actual,
|
|
57
|
+
testResults: [],
|
|
58
|
+
});
|
|
59
|
+
const metricRuleResult = (success, actual) => ({
|
|
60
|
+
success,
|
|
61
|
+
actual,
|
|
62
|
+
testResults: [],
|
|
63
|
+
});
|
|
64
|
+
const metricDeltaWithinThreshold = (delta, threshold, better) => {
|
|
65
|
+
if (better === "lower") {
|
|
66
|
+
return delta <= threshold;
|
|
67
|
+
}
|
|
68
|
+
if (better === "higher") {
|
|
69
|
+
return -delta <= threshold;
|
|
70
|
+
}
|
|
71
|
+
return Math.abs(delta) <= threshold;
|
|
72
|
+
};
|
|
3
73
|
export const maxFailuresRule = {
|
|
4
74
|
rule: "maxFailures",
|
|
5
75
|
message: ({ actual, expected }) => `The number of failed tests ${bold(String(actual))} exceeds the allowed threshold value ${bold(String(expected))}`,
|
|
6
76
|
validate: async ({ trs, expected, state }) => {
|
|
7
|
-
const previous = state.getResult()
|
|
77
|
+
const previous = numberStateValue(state.getResult());
|
|
8
78
|
const failedTrs = trs.filter(filterUnsuccessful);
|
|
9
79
|
const testResults = failedTrs.map((tr) => tr.id);
|
|
10
80
|
const actual = previous + failedTrs.length;
|
|
@@ -20,7 +90,7 @@ export const minTestsCountRule = {
|
|
|
20
90
|
rule: "minTestsCount",
|
|
21
91
|
message: ({ actual, expected }) => `The total number of tests ${bold(String(actual))} is less than the expected threshold value ${bold(String(expected))}`,
|
|
22
92
|
validate: async ({ trs, expected, state }) => {
|
|
23
|
-
const actual = trs.length + (state.getResult()
|
|
93
|
+
const actual = trs.length + numberStateValue(state.getResult());
|
|
24
94
|
state.setResult(actual, []);
|
|
25
95
|
return {
|
|
26
96
|
success: actual >= expected,
|
|
@@ -33,7 +103,7 @@ export const successRateRule = {
|
|
|
33
103
|
rule: "successRate",
|
|
34
104
|
message: ({ actual, expected }) => `Success rate ${bold(String(actual))} is less, than expected ${bold(String(expected))}`,
|
|
35
105
|
validate: async ({ trs, expected, state }) => {
|
|
36
|
-
const previous = state.getResult()
|
|
106
|
+
const previous = successRateStateValue(state.getResult());
|
|
37
107
|
const passedTrs = trs.filter(filterSuccessful);
|
|
38
108
|
const notPassedTrs = trs.filter((tr) => !filterSuccessful(tr));
|
|
39
109
|
const totalCount = previous.totalCount + trs.length;
|
|
@@ -52,7 +122,7 @@ export const maxDurationRule = {
|
|
|
52
122
|
rule: "maxDuration",
|
|
53
123
|
message: ({ actual, expected }) => `Maximum duration of some tests exceed the defined limit; actual ${bold(String(actual))}, expected ${bold(String(expected))}`,
|
|
54
124
|
validate: async ({ trs, expected, state }) => {
|
|
55
|
-
const previous = state.getResult()
|
|
125
|
+
const previous = numberStateValue(state.getResult());
|
|
56
126
|
const actual = Math.max(previous, ...trs.map((tr) => tr.duration ?? 0));
|
|
57
127
|
const tooLongTrs = trs.filter((tr) => (tr.duration ?? 0) > expected);
|
|
58
128
|
const testResults = tooLongTrs.map((tr) => tr.id);
|
|
@@ -66,9 +136,9 @@ export const maxDurationRule = {
|
|
|
66
136
|
};
|
|
67
137
|
export const allTestsContainEnvRule = {
|
|
68
138
|
rule: "allTestsContainEnv",
|
|
69
|
-
message: ({ actual, expected }) => `Not all tests contain the required "${bold(expected)}" environment, ${bold(actual)} tests have different or missing environment`,
|
|
139
|
+
message: ({ actual, expected }) => `Not all tests contain the required "${bold(expected)}" environment, ${bold(String(actual))} tests have different or missing environment`,
|
|
70
140
|
validate: async ({ trs, expected, state }) => {
|
|
71
|
-
const previous = state.getResult()
|
|
141
|
+
const previous = numberStateValue(state.getResult());
|
|
72
142
|
const testsWithoutEnv = trs.filter((tr) => (tr.environment ?? "") !== expected);
|
|
73
143
|
const testResults = testsWithoutEnv.map((tr) => tr.id);
|
|
74
144
|
const actual = testsWithoutEnv.length + previous;
|
|
@@ -84,7 +154,7 @@ export const environmentsTestedRule = {
|
|
|
84
154
|
rule: "environmentsTested",
|
|
85
155
|
message: ({ actual, expected }) => `The following environments were not tested: "${actual.join('", "')}"; expected all of: "${expected.join('", "')}"`,
|
|
86
156
|
validate: async ({ trs, expected, state }) => {
|
|
87
|
-
const previouslyTested = new Set(state.getResult()
|
|
157
|
+
const previouslyTested = new Set(stringArrayStateValue(state.getResult()));
|
|
88
158
|
const batchTested = trs.map((tr) => tr.environment).filter((env) => env != null && env !== "");
|
|
89
159
|
const testedEnvs = new Set([...previouslyTested, ...batchTested]);
|
|
90
160
|
state.setResult([...testedEnvs], []);
|
|
@@ -96,6 +166,62 @@ export const environmentsTestedRule = {
|
|
|
96
166
|
};
|
|
97
167
|
},
|
|
98
168
|
};
|
|
169
|
+
export const metricMaxRule = {
|
|
170
|
+
rule: "metricMax",
|
|
171
|
+
message: ({ actual, expected }) => `${bold(metricRuleTitle(actual))} ${bold(formatMetricValue(actual.value, metricRuleUnit(actual, expected)))} exceeds the allowed maximum ${bold(formatMetricValue(expected.value, metricRuleUnit(actual, expected)))}`,
|
|
172
|
+
validate: async ({ metrics = [], expected }) => {
|
|
173
|
+
const value = metricAverage(metrics, expected.key);
|
|
174
|
+
const actual = metricActual(metrics, expected.key, value ?? Number.NaN);
|
|
175
|
+
return value === undefined ? missingMetricResult(actual) : metricRuleResult(value <= expected.value, actual);
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
export const metricMinRule = {
|
|
179
|
+
rule: "metricMin",
|
|
180
|
+
message: ({ actual, expected }) => `${bold(metricRuleTitle(actual))} ${bold(formatMetricValue(actual.value, metricRuleUnit(actual, expected)))} is below the required minimum ${bold(formatMetricValue(expected.value, metricRuleUnit(actual, expected)))}`,
|
|
181
|
+
validate: async ({ metrics = [], expected }) => {
|
|
182
|
+
const value = metricAverage(metrics, expected.key);
|
|
183
|
+
const actual = metricActual(metrics, expected.key, value ?? Number.NaN);
|
|
184
|
+
return value === undefined ? missingMetricResult(actual) : metricRuleResult(value >= expected.value, actual);
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
export const metricMaxDeltaRule = {
|
|
188
|
+
rule: "metricMaxDelta",
|
|
189
|
+
message: ({ actual, expected }) => `${bold(metricRuleTitle(actual))} changed by ${bold(formatMetricValue(actual.value, metricRuleUnit(actual, expected)))}, which exceeds ${bold(formatMetricValue(expected.value, metricRuleUnit(actual, expected)))}`,
|
|
190
|
+
validate: async ({ metrics = [], previousHistory = [], expected }) => {
|
|
191
|
+
const current = metricAverage(metrics, expected.key);
|
|
192
|
+
if (current === undefined) {
|
|
193
|
+
return missingMetricResult(metricActual(metrics, expected.key, Number.NaN));
|
|
194
|
+
}
|
|
195
|
+
const previous = previousMetricValue(previousHistory, expected.key);
|
|
196
|
+
if (previous === undefined) {
|
|
197
|
+
return metricRuleResult(true, metricActual(metrics, expected.key, 0));
|
|
198
|
+
}
|
|
199
|
+
const value = current - previous;
|
|
200
|
+
const actual = metricActual(metrics, expected.key, value);
|
|
201
|
+
const better = metrics.find((metric) => metric.key === expected.key)?.better;
|
|
202
|
+
return metricRuleResult(metricDeltaWithinThreshold(value, expected.value, better), actual);
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
export const metricMaxDeltaPercentRule = {
|
|
206
|
+
rule: "metricMaxDeltaPercent",
|
|
207
|
+
message: ({ actual, expected }) => `${bold(metricRuleTitle(actual))} changed by ${bold(formatMetricValue(actual.value, "%"))}, which exceeds ${bold(formatMetricValue(expected.value, "%"))}`,
|
|
208
|
+
validate: async ({ metrics = [], previousHistory = [], expected }) => {
|
|
209
|
+
const current = metricAverage(metrics, expected.key);
|
|
210
|
+
if (current === undefined) {
|
|
211
|
+
return missingMetricResult(metricActual(metrics, expected.key, Number.NaN));
|
|
212
|
+
}
|
|
213
|
+
const previous = previousMetricValue(previousHistory, expected.key);
|
|
214
|
+
if (previous === undefined) {
|
|
215
|
+
return metricRuleResult(true, metricActual(metrics, expected.key, 0));
|
|
216
|
+
}
|
|
217
|
+
const value = previous !== 0 ? ((current - previous) / Math.abs(previous)) * 100 : Number.NaN;
|
|
218
|
+
const actual = metricActual(metrics, expected.key, value);
|
|
219
|
+
const better = metrics.find((metric) => metric.key === expected.key)?.better;
|
|
220
|
+
return Number.isFinite(value)
|
|
221
|
+
? metricRuleResult(metricDeltaWithinThreshold(value, expected.value, better), actual)
|
|
222
|
+
: missingMetricResult(actual);
|
|
223
|
+
},
|
|
224
|
+
};
|
|
99
225
|
export const qualityGateDefaultRules = [
|
|
100
226
|
maxFailuresRule,
|
|
101
227
|
minTestsCountRule,
|
|
@@ -103,4 +229,8 @@ export const qualityGateDefaultRules = [
|
|
|
103
229
|
maxDurationRule,
|
|
104
230
|
allTestsContainEnvRule,
|
|
105
231
|
environmentsTestedRule,
|
|
232
|
+
metricMaxRule,
|
|
233
|
+
metricMinRule,
|
|
234
|
+
metricMaxDeltaRule,
|
|
235
|
+
metricMaxDeltaPercentRule,
|
|
106
236
|
];
|
package/dist/report.js
CHANGED
|
@@ -9,14 +9,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _AllureReport_instances, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_realtimeChannel, _AllureReport_realtimeUpdateScheduler, _AllureReport_realTime, _AllureReport_hideLabels, _AllureReport_output, _AllureReport_history, _AllureReport_appendHistory, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_environments, _AllureReport_globalAttachments, _AllureReport_knownIssuesPath, _AllureReport_dumpTempDirs, _AllureReport_state, _AllureReport_executionStage, _AllureReport_historyDataPoint, _AllureReport_summaryPath, _AllureReport_testResultsRegistryPath, _AllureReport_summariesByPluginId, _AllureReport_publishedRemoteHrefs, _AllureReport_published, _AllureReport_endGeneratePerfSpan, _AllureReport_publish, _AllureReport_runRealtimeUpdate, _AllureReport_restoreStateDumps, _AllureReport_getReportsToPublish, _AllureReport_cleanupFailedRemoteReport, _AllureReport_logPublishError, _AllureReport_applyPublishLinksToSummaries, _AllureReport_cloneSummariesByPluginId, _AllureReport_writeSummaryFiles, _AllureReport_writeTestResultRegistry, _AllureReport_generateRootSummary, _AllureReport_finishGeneratePerfSpan, _AllureReport_finishPerfMetrics, _AllureReport_eachPlugin, _AllureReport_getPluginState;
|
|
12
|
+
var _AllureReport_instances, _AllureReport_ci, _AllureReport_store, _AllureReport_readers, _AllureReport_plugins, _AllureReport_reportFiles, _AllureReport_realtimeChannel, _AllureReport_realtimeUpdateScheduler, _AllureReport_realTime, _AllureReport_hideLabels, _AllureReport_output, _AllureReport_history, _AllureReport_appendHistory, _AllureReport_allureServiceClient, _AllureReport_qualityGate, _AllureReport_dump, _AllureReport_categories, _AllureReport_environments, _AllureReport_globalAttachments, _AllureReport_knownIssuesPath, _AllureReport_dumpTempDirs, _AllureReport_cwd, _AllureReport_state, _AllureReport_executionStage, _AllureReport_historyDataPoint, _AllureReport_summaryPath, _AllureReport_testResultsRegistryPath, _AllureReport_summariesByPluginId, _AllureReport_publishedRemoteHrefs, _AllureReport_artifactFilesByPath, _AllureReport_published, _AllureReport_endGeneratePerfSpan, _AllureReport_createHistoryDataPoint, _AllureReport_ingestSelfPerfMetrics, _AllureReport_publish, _AllureReport_getCwd, _AllureReport_runRealtimeUpdate, _AllureReport_recordArtifact, _AllureReport_restoreStateDumps, _AllureReport_getReportsToPublish, _AllureReport_cleanupFailedRemoteReport, _AllureReport_logPublishError, _AllureReport_applyPublishLinksToSummaries, _AllureReport_cloneSummariesByPluginId, _AllureReport_writeSummaryFiles, _AllureReport_writeTestResultRegistry, _AllureReport_getRootRemoteReportFiles, _AllureReport_writeQualityGateFiles, _AllureReport_finishArtifactsManifest, _AllureReport_generateRootSummary, _AllureReport_finishGeneratePerfSpan, _AllureReport_finishPerfMetrics, _AllureReport_eachPlugin, _AllureReport_getPluginState;
|
|
13
13
|
import console from "node:console";
|
|
14
14
|
import { randomUUID } from "node:crypto";
|
|
15
15
|
import { once } from "node:events";
|
|
16
16
|
import { createReadStream, createWriteStream, existsSync, readFileSync } from "node:fs";
|
|
17
17
|
import { lstat, mkdtemp, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
18
18
|
import { tmpdir } from "node:os";
|
|
19
|
-
import { basename, dirname, join, resolve
|
|
19
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
20
20
|
import { promisify } from "node:util";
|
|
21
21
|
import { detect } from "@allurereport/ci";
|
|
22
22
|
import { createProgressLogger } from "@allurereport/cli-commons";
|
|
@@ -35,8 +35,9 @@ import { DefaultPluginState, PluginFiles } from "./plugin.js";
|
|
|
35
35
|
import { QualityGate } from "./qualityGate/index.js";
|
|
36
36
|
import { writeKnownIssues } from "./resolutions.js";
|
|
37
37
|
import { DefaultAllureStore } from "./store/store.js";
|
|
38
|
+
import { ARTIFACTS_MANIFEST_FILENAME, createReportArtifact, deduplicateDumpInputs, } from "./utils/artifacts.js";
|
|
38
39
|
import { environmentIdentityById, environmentIdentityByName } from "./utils/environment.js";
|
|
39
|
-
import { measurePerf, PERF_METRIC_NAMES, PERF_METRIC_PREFIXES, startPerfSpan, writePerfMetrics } from "./utils/perf.js";
|
|
40
|
+
import { getPerfMetricsResults, isPerfMetricsEnabled, measurePerf, PERF_METRIC_NAMES, PERF_METRIC_PREFIXES, perfMetricsFileName, startPerfSpan, writePerfMetrics, } from "./utils/perf.js";
|
|
40
41
|
import { RealtimeChannel } from "./utils/realtimeChannel.js";
|
|
41
42
|
import { RealtimeUpdateScheduler } from "./utils/realtimeUpdateScheduler.js";
|
|
42
43
|
import { resolveDumpAttachmentPath, UnsafeDumpPathError } from "./utils/safeDumpPath.js";
|
|
@@ -45,6 +46,12 @@ const INIT_REQUIRED_ERROR_MESSAGE = "report is not initialised. Call the start()
|
|
|
45
46
|
const DEFAULT_READ_CONCURRENCY = 64;
|
|
46
47
|
const MAX_READ_CONCURRENCY = 256;
|
|
47
48
|
const TEST_RESULTS_REGISTRY_FILENAME = "test-results.json";
|
|
49
|
+
const QUALITY_GATE_RESULTS_FILENAME = "quality-gate.json";
|
|
50
|
+
const ROOT_INTEGRATION_FILENAMES = new Set([
|
|
51
|
+
TEST_RESULTS_REGISTRY_FILENAME,
|
|
52
|
+
QUALITY_GATE_RESULTS_FILENAME,
|
|
53
|
+
ARTIFACTS_MANIFEST_FILENAME,
|
|
54
|
+
]);
|
|
48
55
|
const readConcurrency = () => {
|
|
49
56
|
const parsed = Number.parseInt(process.env.ALLURE_READ_CONCURRENCY ?? "", 10);
|
|
50
57
|
if (!Number.isFinite(parsed)) {
|
|
@@ -92,6 +99,7 @@ export class AllureReport {
|
|
|
92
99
|
_AllureReport_globalAttachments.set(this, void 0);
|
|
93
100
|
_AllureReport_knownIssuesPath.set(this, void 0);
|
|
94
101
|
_AllureReport_dumpTempDirs.set(this, []);
|
|
102
|
+
_AllureReport_cwd.set(this, void 0);
|
|
95
103
|
_AllureReport_state.set(this, void 0);
|
|
96
104
|
_AllureReport_executionStage.set(this, "init");
|
|
97
105
|
_AllureReport_historyDataPoint.set(this, void 0);
|
|
@@ -99,8 +107,28 @@ export class AllureReport {
|
|
|
99
107
|
_AllureReport_testResultsRegistryPath.set(this, void 0);
|
|
100
108
|
_AllureReport_summariesByPluginId.set(this, new Map());
|
|
101
109
|
_AllureReport_publishedRemoteHrefs.set(this, new Set());
|
|
110
|
+
_AllureReport_artifactFilesByPath.set(this, new Map());
|
|
102
111
|
_AllureReport_published.set(this, false);
|
|
103
112
|
_AllureReport_endGeneratePerfSpan.set(this, void 0);
|
|
113
|
+
_AllureReport_createHistoryDataPoint.set(this, async () => {
|
|
114
|
+
const allTrs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
|
|
115
|
+
const allTcs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
|
|
116
|
+
return createHistory(this.reportUuid, this.reportName, allTcs, allTrs, this.reportUrl, await __classPrivateFieldGet(this, _AllureReport_store, "f").allMetrics());
|
|
117
|
+
});
|
|
118
|
+
_AllureReport_ingestSelfPerfMetrics.set(this, async () => {
|
|
119
|
+
if (!isPerfMetricsEnabled()) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const results = getPerfMetricsResults();
|
|
123
|
+
if (results.length === 0) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const originalFileName = perfMetricsFileName(this.reportUuid);
|
|
127
|
+
await __classPrivateFieldGet(this, _AllureReport_store, "f").visitMetrics(results, {
|
|
128
|
+
readerId: "api",
|
|
129
|
+
metadata: { originalFileName },
|
|
130
|
+
});
|
|
131
|
+
});
|
|
104
132
|
_AllureReport_publish.set(this, async () => {
|
|
105
133
|
if (__classPrivateFieldGet(this, _AllureReport_published, "f")) {
|
|
106
134
|
return;
|
|
@@ -110,12 +138,13 @@ export class AllureReport {
|
|
|
110
138
|
}
|
|
111
139
|
let historyPoint = __classPrivateFieldGet(this, _AllureReport_historyDataPoint, "f");
|
|
112
140
|
if (!historyPoint) {
|
|
113
|
-
|
|
114
|
-
const allTcs = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
|
|
115
|
-
historyPoint = createHistory(this.reportUuid, this.reportName, allTcs, allTrs, this.reportUrl);
|
|
141
|
+
historyPoint = await __classPrivateFieldGet(this, _AllureReport_createHistoryDataPoint, "f").call(this);
|
|
116
142
|
__classPrivateFieldSet(this, _AllureReport_historyDataPoint, historyPoint, "f");
|
|
117
143
|
}
|
|
118
144
|
await __classPrivateFieldGet(this, _AllureReport_writeTestResultRegistry, "f").call(this);
|
|
145
|
+
if (__classPrivateFieldGet(this, _AllureReport_qualityGate, "f")) {
|
|
146
|
+
await __classPrivateFieldGet(this, _AllureReport_writeQualityGateFiles, "f").call(this);
|
|
147
|
+
}
|
|
119
148
|
await __classPrivateFieldGet(this, _AllureReport_writeSummaryFiles, "f").call(this);
|
|
120
149
|
await __classPrivateFieldGet(this, _AllureReport_generateRootSummary, "f").call(this);
|
|
121
150
|
if (__classPrivateFieldGet(this, _AllureReport_realTime, "f") || !__classPrivateFieldGet(this, _AllureReport_allureServiceClient, "f")) {
|
|
@@ -131,8 +160,9 @@ export class AllureReport {
|
|
|
131
160
|
const linksByPluginId = {};
|
|
132
161
|
const summariesSnapshot = __classPrivateFieldGet(this, _AllureReport_cloneSummariesByPluginId, "f").call(this);
|
|
133
162
|
const uploadProgressMessage = reportsToPublish.length === 1 ? `Publishing "${reportsToPublish[0].pluginId}" report` : "Publishing reports";
|
|
163
|
+
const rootRemoteReportFiles = __classPrivateFieldGet(this, _AllureReport_getRootRemoteReportFiles, "f").call(this);
|
|
134
164
|
const totalFilesToUpload = reportsToPublish.reduce((acc, report) => acc + Object.keys(report.files).length, 0) +
|
|
135
|
-
(
|
|
165
|
+
Object.keys(rootRemoteReportFiles).length;
|
|
136
166
|
let summariesMutated = false;
|
|
137
167
|
let reportCreated = false;
|
|
138
168
|
let publishErrorMessage = "Report upload has failed, the report won't be published";
|
|
@@ -167,11 +197,11 @@ export class AllureReport {
|
|
|
167
197
|
linksByPluginId[report.pluginId] = uploadResult.indexHref;
|
|
168
198
|
}
|
|
169
199
|
}
|
|
170
|
-
if (
|
|
200
|
+
if (Object.keys(rootRemoteReportFiles).length > 0) {
|
|
171
201
|
publishErrorMessage = "Test results registry upload has failed, the report won't be published";
|
|
172
202
|
await client.uploadReport({
|
|
173
203
|
reportUuid: this.reportUuid,
|
|
174
|
-
files:
|
|
204
|
+
files: rootRemoteReportFiles,
|
|
175
205
|
onProgress: incrementUploadProgress,
|
|
176
206
|
});
|
|
177
207
|
}
|
|
@@ -292,9 +322,15 @@ export class AllureReport {
|
|
|
292
322
|
return __classPrivateFieldGet(this, _AllureReport_qualityGate, "f").validate({
|
|
293
323
|
trs: trs.filter(Boolean),
|
|
294
324
|
state,
|
|
325
|
+
metrics: await __classPrivateFieldGet(this, _AllureReport_store, "f").allMetrics(),
|
|
326
|
+
previousHistory: (await __classPrivateFieldGet(this, _AllureReport_store, "f").allHistoryDataPoints()).filter(({ uuid }) => uuid !== this.reportUuid),
|
|
295
327
|
environment: qualityGateEnvironment,
|
|
296
328
|
});
|
|
297
329
|
};
|
|
330
|
+
_AllureReport_getCwd.set(this, () => {
|
|
331
|
+
__classPrivateFieldSet(this, _AllureReport_cwd, __classPrivateFieldGet(this, _AllureReport_cwd, "f") ?? resolve(process.cwd()), "f");
|
|
332
|
+
return __classPrivateFieldGet(this, _AllureReport_cwd, "f");
|
|
333
|
+
});
|
|
298
334
|
this.start = async () => {
|
|
299
335
|
await __classPrivateFieldGet(this, _AllureReport_store, "f").readHistory();
|
|
300
336
|
if (__classPrivateFieldGet(this, _AllureReport_executionStage, "f") === "running") {
|
|
@@ -305,22 +341,17 @@ export class AllureReport {
|
|
|
305
341
|
}
|
|
306
342
|
__classPrivateFieldSet(this, _AllureReport_executionStage, "running", "f");
|
|
307
343
|
__classPrivateFieldSet(this, _AllureReport_endGeneratePerfSpan, startPerfSpan(PERF_METRIC_NAMES.generateTotal), "f");
|
|
308
|
-
const cwd = resolve(process.cwd());
|
|
309
|
-
const cwdWithSep = cwd.endsWith(sep) ? cwd : `${cwd}${sep}`;
|
|
310
344
|
if (__classPrivateFieldGet(this, _AllureReport_globalAttachments, "f")?.length) {
|
|
345
|
+
const cwd = __classPrivateFieldGet(this, _AllureReport_getCwd, "f").call(this);
|
|
311
346
|
const matchedFiles = new Set();
|
|
312
347
|
for (const pattern of __classPrivateFieldGet(this, _AllureReport_globalAttachments, "f")) {
|
|
313
348
|
const files = await glob(pattern, { cwd, nodir: true, absolute: true });
|
|
314
|
-
files.forEach((filePath) => matchedFiles.add(filePath));
|
|
349
|
+
files.forEach((filePath) => matchedFiles.add(resolve(cwd, filePath)));
|
|
315
350
|
}
|
|
316
|
-
for (const
|
|
317
|
-
const absoluteFilePath = resolve(filePath);
|
|
318
|
-
const isInsideCwd = absoluteFilePath === cwd || absoluteFilePath.startsWith(cwdWithSep);
|
|
319
|
-
if (!isInsideCwd) {
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
351
|
+
for (const absoluteFilePath of matchedFiles) {
|
|
322
352
|
const originalFileName = basename(absoluteFilePath);
|
|
323
353
|
__classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher.sendGlobalAttachment(new PathResultFile(absoluteFilePath, originalFileName), originalFileName);
|
|
354
|
+
__classPrivateFieldGet(this, _AllureReport_recordArtifact, "f").call(this, absoluteFilePath, originalFileName);
|
|
324
355
|
}
|
|
325
356
|
}
|
|
326
357
|
await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, true, async (plugin, context) => {
|
|
@@ -387,7 +418,7 @@ export class AllureReport {
|
|
|
387
418
|
const addJsonDumpEntry = async (entryName, value) => {
|
|
388
419
|
await addRequiredDumpEntry(Buffer.from(JSON.stringify(value)), entryName);
|
|
389
420
|
};
|
|
390
|
-
const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = {}, globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexTestResultByResolutionIssue = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, resolutionIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], }) => [
|
|
421
|
+
const dumpJsonEntries = ({ testResults, testCases, fixtures, attachments, environments, reportVariables, checkResults = {}, globalAttachmentIds = [], globalErrors = [], indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexTestResultByResolutionIssue = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, resolutionIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], metrics = [], }) => [
|
|
391
422
|
[AllureStoreDumpFiles.TestResults, testResults],
|
|
392
423
|
[AllureStoreDumpFiles.TestCases, testCases],
|
|
393
424
|
[AllureStoreDumpFiles.Fixtures, fixtures],
|
|
@@ -406,6 +437,7 @@ export class AllureReport {
|
|
|
406
437
|
[AllureStoreDumpFiles.IndexFixturesByTestResult, indexFixturesByTestResult],
|
|
407
438
|
[AllureStoreDumpFiles.QualityGateResults, qualityGateResults],
|
|
408
439
|
[AllureStoreDumpFiles.TestResultIngestOrder, testResultIdsIngestOrder],
|
|
440
|
+
[AllureStoreDumpFiles.Metrics, metrics],
|
|
409
441
|
];
|
|
410
442
|
let dumpError;
|
|
411
443
|
dumpArchive.pipe(dumpArchiveWriteStream);
|
|
@@ -473,10 +505,18 @@ export class AllureReport {
|
|
|
473
505
|
};
|
|
474
506
|
this.restoreState = async (dumps) => {
|
|
475
507
|
__classPrivateFieldGet(this, _AllureReport_store, "f").resetIngestOrder();
|
|
476
|
-
await __classPrivateFieldGet(this, _AllureReport_restoreStateDumps, "f").call(this, dumps);
|
|
508
|
+
await __classPrivateFieldGet(this, _AllureReport_restoreStateDumps, "f").call(this, dumps.map((path) => ({ artifactPath: path, path })));
|
|
477
509
|
};
|
|
510
|
+
_AllureReport_recordArtifact.set(this, (filePath, name = basename(filePath)) => {
|
|
511
|
+
const artifact = createReportArtifact(filePath, __classPrivateFieldGet(this, _AllureReport_getCwd, "f").call(this), name);
|
|
512
|
+
if (!__classPrivateFieldGet(this, _AllureReport_artifactFilesByPath, "f").has(artifact.path)) {
|
|
513
|
+
__classPrivateFieldGet(this, _AllureReport_artifactFilesByPath, "f").set(artifact.path, artifact);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
478
516
|
_AllureReport_restoreStateDumps.set(this, async (dumps) => measurePerf(PERF_METRIC_NAMES.restoreStateTotal, async () => {
|
|
479
|
-
|
|
517
|
+
let restoredCount = 0;
|
|
518
|
+
for (const { artifactPath, path: dump, recordArtifact = true } of deduplicateDumpInputs(dumps, __classPrivateFieldGet(this, _AllureReport_getCwd, "f").call(this))) {
|
|
519
|
+
const artifactFilePath = artifactPath ?? dump;
|
|
480
520
|
await measurePerf(PERF_METRIC_NAMES.restoreStateDump, async () => {
|
|
481
521
|
if (!existsSync(dump)) {
|
|
482
522
|
console.error(`Failed to restore state from "${dump}", continuing without it`);
|
|
@@ -505,14 +545,24 @@ export class AllureReport {
|
|
|
505
545
|
entryName.toLowerCase().endsWith(".zip"));
|
|
506
546
|
if (nestedDumpEntries.length > 0) {
|
|
507
547
|
const nestedDumpsTempDir = await mkdtemp(join(tmpdir(), `${basename(dump, ".zip")}-nested-`));
|
|
508
|
-
const
|
|
548
|
+
const nestedDumps = [];
|
|
509
549
|
__classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f").push(nestedDumpsTempDir);
|
|
510
550
|
for (const [entryName] of nestedDumpEntries) {
|
|
511
|
-
const nestedDumpPath = join(nestedDumpsTempDir, `${
|
|
551
|
+
const nestedDumpPath = join(nestedDumpsTempDir, `${nestedDumps.length}-${basename(entryName)}`);
|
|
512
552
|
await writeFile(nestedDumpPath, await dumpArchive.entryData(entryName));
|
|
513
|
-
|
|
553
|
+
nestedDumps.push({
|
|
554
|
+
artifactPath: artifactFilePath,
|
|
555
|
+
path: nestedDumpPath,
|
|
556
|
+
recordArtifact: false,
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
const nestedRestoredCount = await __classPrivateFieldGet(this, _AllureReport_restoreStateDumps, "f").call(this, nestedDumps);
|
|
560
|
+
if (nestedRestoredCount > 0) {
|
|
561
|
+
restoredCount += 1;
|
|
562
|
+
if (recordArtifact) {
|
|
563
|
+
__classPrivateFieldGet(this, _AllureReport_recordArtifact, "f").call(this, artifactFilePath);
|
|
564
|
+
}
|
|
514
565
|
}
|
|
515
|
-
await __classPrivateFieldGet(this, _AllureReport_restoreStateDumps, "f").call(this, nestedDumpPaths);
|
|
516
566
|
return;
|
|
517
567
|
}
|
|
518
568
|
}
|
|
@@ -534,6 +584,7 @@ export class AllureReport {
|
|
|
534
584
|
const resolutionIssuesEntry = await optionalEntryData(AllureStoreDumpFiles.ResolutionIssues);
|
|
535
585
|
const qualityGateResultsEntry = await requiredEntryData(AllureStoreDumpFiles.QualityGateResults);
|
|
536
586
|
const testResultIngestOrderEntry = await optionalEntryData(AllureStoreDumpFiles.TestResultIngestOrder);
|
|
587
|
+
const metricsEntry = await optionalEntryData(AllureStoreDumpFiles.Metrics);
|
|
537
588
|
const attachmentsLinks = JSON.parse(attachmentsEntry.toString("utf8"));
|
|
538
589
|
const attachmentsEntries = dumpEntriesList.reduce((acc, [entryName, entry]) => {
|
|
539
590
|
switch (entryName) {
|
|
@@ -555,6 +606,7 @@ export class AllureReport {
|
|
|
555
606
|
case AllureStoreDumpFiles.IndexFixturesByTestResult:
|
|
556
607
|
case AllureStoreDumpFiles.QualityGateResults:
|
|
557
608
|
case AllureStoreDumpFiles.TestResultIngestOrder:
|
|
609
|
+
case AllureStoreDumpFiles.Metrics:
|
|
558
610
|
return acc;
|
|
559
611
|
default:
|
|
560
612
|
if (entry.isDirectory || !attachmentsLinks[entryName] || attachmentsLinks[entryName].missed) {
|
|
@@ -588,6 +640,7 @@ export class AllureReport {
|
|
|
588
640
|
testResultIdsIngestOrder: testResultIngestOrderEntry
|
|
589
641
|
? JSON.parse(testResultIngestOrderEntry.toString("utf8"))
|
|
590
642
|
: [],
|
|
643
|
+
metrics: metricsEntry ? JSON.parse(metricsEntry.toString("utf8")) : [],
|
|
591
644
|
};
|
|
592
645
|
const dumpTempDir = await mkdtemp(join(tmpdir(), basename(dump, ".zip")));
|
|
593
646
|
const resultsAttachments = {};
|
|
@@ -614,6 +667,10 @@ export class AllureReport {
|
|
|
614
667
|
});
|
|
615
668
|
await measurePerf(PERF_METRIC_NAMES.restoreStateStoreRestore, async () => __classPrivateFieldGet(this, _AllureReport_store, "f").restoreState(dumpState, resultsAttachments));
|
|
616
669
|
console.info(`Successfully restored state from "${dump}"`);
|
|
670
|
+
restoredCount += 1;
|
|
671
|
+
if (recordArtifact) {
|
|
672
|
+
__classPrivateFieldGet(this, _AllureReport_recordArtifact, "f").call(this, artifactFilePath);
|
|
673
|
+
}
|
|
617
674
|
}
|
|
618
675
|
catch (err) {
|
|
619
676
|
restoreError = err;
|
|
@@ -637,6 +694,7 @@ export class AllureReport {
|
|
|
637
694
|
}
|
|
638
695
|
});
|
|
639
696
|
}
|
|
697
|
+
return restoredCount;
|
|
640
698
|
}));
|
|
641
699
|
_AllureReport_getReportsToPublish.set(this, async () => {
|
|
642
700
|
const reports = [];
|
|
@@ -709,6 +767,25 @@ export class AllureReport {
|
|
|
709
767
|
const registry = createTestResultRegistry(testResults);
|
|
710
768
|
__classPrivateFieldSet(this, _AllureReport_testResultsRegistryPath, await __classPrivateFieldGet(this, _AllureReport_reportFiles, "f").addFile(TEST_RESULTS_REGISTRY_FILENAME, Buffer.from(JSON.stringify(registry))), "f");
|
|
711
769
|
});
|
|
770
|
+
_AllureReport_getRootRemoteReportFiles.set(this, () => ({
|
|
771
|
+
...(__classPrivateFieldGet(this, _AllureReport_testResultsRegistryPath, "f") ? { [TEST_RESULTS_REGISTRY_FILENAME]: __classPrivateFieldGet(this, _AllureReport_testResultsRegistryPath, "f") } : {}),
|
|
772
|
+
}));
|
|
773
|
+
_AllureReport_writeQualityGateFiles.set(this, async () => {
|
|
774
|
+
const qualityGateResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").qualityGateResults();
|
|
775
|
+
await __classPrivateFieldGet(this, _AllureReport_reportFiles, "f").addFile(QUALITY_GATE_RESULTS_FILENAME, Buffer.from(JSON.stringify(qualityGateResults)));
|
|
776
|
+
});
|
|
777
|
+
_AllureReport_finishArtifactsManifest.set(this, async () => {
|
|
778
|
+
if (__classPrivateFieldGet(this, _AllureReport_artifactFilesByPath, "f").size === 0) {
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const manifest = [...__classPrivateFieldGet(this, _AllureReport_artifactFilesByPath, "f").values()];
|
|
782
|
+
try {
|
|
783
|
+
await writeFile(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), ARTIFACTS_MANIFEST_FILENAME), JSON.stringify(manifest));
|
|
784
|
+
}
|
|
785
|
+
catch (err) {
|
|
786
|
+
console.error("Failed to write Allure artifacts manifest", err);
|
|
787
|
+
}
|
|
788
|
+
});
|
|
712
789
|
_AllureReport_generateRootSummary.set(this, async () => {
|
|
713
790
|
const summaries = [...__classPrivateFieldGet(this, _AllureReport_summariesByPluginId, "f").values()].map(clonePluginSummary);
|
|
714
791
|
if (summaries.length > 1) {
|
|
@@ -724,9 +801,6 @@ export class AllureReport {
|
|
|
724
801
|
throw new Error(INIT_REQUIRED_ERROR_MESSAGE);
|
|
725
802
|
}
|
|
726
803
|
try {
|
|
727
|
-
const testResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestResults();
|
|
728
|
-
const testCases = await __classPrivateFieldGet(this, _AllureReport_store, "f").allTestCases();
|
|
729
|
-
__classPrivateFieldSet(this, _AllureReport_historyDataPoint, createHistory(this.reportUuid, this.reportName, testCases, testResults, this.reportUrl), "f");
|
|
730
804
|
__classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").close();
|
|
731
805
|
try {
|
|
732
806
|
await __classPrivateFieldGet(this, _AllureReport_realtimeUpdateScheduler, "f").close();
|
|
@@ -747,6 +821,8 @@ export class AllureReport {
|
|
|
747
821
|
});
|
|
748
822
|
});
|
|
749
823
|
__classPrivateFieldGet(this, _AllureReport_finishGeneratePerfSpan, "f").call(this);
|
|
824
|
+
await __classPrivateFieldGet(this, _AllureReport_ingestSelfPerfMetrics, "f").call(this);
|
|
825
|
+
__classPrivateFieldSet(this, _AllureReport_historyDataPoint, await __classPrivateFieldGet(this, _AllureReport_createHistoryDataPoint, "f").call(this), "f");
|
|
750
826
|
await __classPrivateFieldGet(this, _AllureReport_eachPlugin, "f").call(this, false, async (plugin, context) => {
|
|
751
827
|
const summary = await plugin?.info?.(context, __classPrivateFieldGet(this, _AllureReport_store, "f"));
|
|
752
828
|
if (!summary) {
|
|
@@ -781,7 +857,7 @@ export class AllureReport {
|
|
|
781
857
|
const reportPath = join(__classPrivateFieldGet(this, _AllureReport_output, "f"), outputDirectoryEntries[0].file);
|
|
782
858
|
const reportContent = await readdir(reportPath);
|
|
783
859
|
for (const entry of reportContent) {
|
|
784
|
-
if (entry
|
|
860
|
+
if (ROOT_INTEGRATION_FILENAMES.has(entry)) {
|
|
785
861
|
continue;
|
|
786
862
|
}
|
|
787
863
|
const currentFilePath = join(reportPath, entry);
|
|
@@ -790,6 +866,7 @@ export class AllureReport {
|
|
|
790
866
|
}
|
|
791
867
|
await rm(reportPath, { recursive: true });
|
|
792
868
|
}
|
|
869
|
+
await __classPrivateFieldGet(this, _AllureReport_finishArtifactsManifest, "f").call(this);
|
|
793
870
|
for (const dir of __classPrivateFieldGet(this, _AllureReport_dumpTempDirs, "f")) {
|
|
794
871
|
try {
|
|
795
872
|
await rm(dir, { recursive: true });
|
|
@@ -818,11 +895,6 @@ export class AllureReport {
|
|
|
818
895
|
console.info(`- ${href}`);
|
|
819
896
|
});
|
|
820
897
|
}
|
|
821
|
-
if (!__classPrivateFieldGet(this, _AllureReport_qualityGate, "f")) {
|
|
822
|
-
return;
|
|
823
|
-
}
|
|
824
|
-
const qualityGateResults = await __classPrivateFieldGet(this, _AllureReport_store, "f").qualityGateResultsByEnv();
|
|
825
|
-
await writeFile(join(__classPrivateFieldGet(this, _AllureReport_output, "f"), "quality-gate.json"), JSON.stringify(qualityGateResults));
|
|
826
898
|
}
|
|
827
899
|
finally {
|
|
828
900
|
await __classPrivateFieldGet(this, _AllureReport_finishPerfMetrics, "f").call(this);
|
|
@@ -835,7 +907,7 @@ export class AllureReport {
|
|
|
835
907
|
_AllureReport_finishPerfMetrics.set(this, async () => {
|
|
836
908
|
__classPrivateFieldGet(this, _AllureReport_finishGeneratePerfSpan, "f").call(this);
|
|
837
909
|
try {
|
|
838
|
-
await writePerfMetrics(__classPrivateFieldGet(this, _AllureReport_output, "f"));
|
|
910
|
+
await writePerfMetrics(__classPrivateFieldGet(this, _AllureReport_output, "f"), perfMetricsFileName(this.reportUuid));
|
|
839
911
|
}
|
|
840
912
|
catch (err) {
|
|
841
913
|
console.error("Failed to write Allure performance metrics", err);
|
|
@@ -893,7 +965,7 @@ export class AllureReport {
|
|
|
893
965
|
}
|
|
894
966
|
}
|
|
895
967
|
});
|
|
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;
|
|
968
|
+
const { name, readers = [allure1, allure2, cucumberjson, junitXml, attachments], plugins = [], resolutions, reportFiles, realTime, historyPath, historyLimit, appendHistory, defaultLabels = {}, variables = {}, environment, allowedEnvironments, environments, output, hideLabels, qualityGate, performance, dump, categories, allureService, globalAttachments, cwd, } = opts;
|
|
897
969
|
const allureServiceAccessToken = allureService?.accessToken;
|
|
898
970
|
if (allureServiceAccessToken) {
|
|
899
971
|
const allureServiceClientConfig = {
|
|
@@ -907,6 +979,7 @@ export class AllureReport {
|
|
|
907
979
|
: undefined, "f");
|
|
908
980
|
}
|
|
909
981
|
this.reportUuid = randomUUID();
|
|
982
|
+
__classPrivateFieldSet(this, _AllureReport_cwd, cwd ? resolve(cwd) : undefined, "f");
|
|
910
983
|
__classPrivateFieldSet(this, _AllureReport_ci, detect(), "f");
|
|
911
984
|
const reportTitleSuffix = __classPrivateFieldGet(this, _AllureReport_ci, "f")?.pullRequestName ?? __classPrivateFieldGet(this, _AllureReport_ci, "f")?.jobRunName;
|
|
912
985
|
this.reportName = [name, reportTitleSuffix].filter(Boolean).join(" – ");
|
|
@@ -946,6 +1019,7 @@ export class AllureReport {
|
|
|
946
1019
|
defaultLabels,
|
|
947
1020
|
environment,
|
|
948
1021
|
allowedEnvironments,
|
|
1022
|
+
performance,
|
|
949
1023
|
}), "f");
|
|
950
1024
|
__classPrivateFieldSet(this, _AllureReport_readers, [...readers], "f");
|
|
951
1025
|
__classPrivateFieldSet(this, _AllureReport_plugins, [...plugins], "f");
|
|
@@ -965,6 +1039,6 @@ export class AllureReport {
|
|
|
965
1039
|
return __classPrivateFieldGet(this, _AllureReport_realtimeChannel, "f").dispatcher;
|
|
966
1040
|
}
|
|
967
1041
|
}
|
|
968
|
-
_AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_realtimeChannel = new WeakMap(), _AllureReport_realtimeUpdateScheduler = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_hideLabels = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_appendHistory = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_environments = new WeakMap(), _AllureReport_globalAttachments = new WeakMap(), _AllureReport_knownIssuesPath = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_historyDataPoint = new WeakMap(), _AllureReport_summaryPath = new WeakMap(), _AllureReport_testResultsRegistryPath = new WeakMap(), _AllureReport_summariesByPluginId = new WeakMap(), _AllureReport_publishedRemoteHrefs = new WeakMap(), _AllureReport_published = new WeakMap(), _AllureReport_endGeneratePerfSpan = new WeakMap(), _AllureReport_publish = new WeakMap(), _AllureReport_runRealtimeUpdate = new WeakMap(), _AllureReport_restoreStateDumps = new WeakMap(), _AllureReport_getReportsToPublish = new WeakMap(), _AllureReport_cleanupFailedRemoteReport = new WeakMap(), _AllureReport_logPublishError = new WeakMap(), _AllureReport_applyPublishLinksToSummaries = new WeakMap(), _AllureReport_cloneSummariesByPluginId = new WeakMap(), _AllureReport_writeSummaryFiles = new WeakMap(), _AllureReport_writeTestResultRegistry = new WeakMap(), _AllureReport_generateRootSummary = new WeakMap(), _AllureReport_finishGeneratePerfSpan = new WeakMap(), _AllureReport_finishPerfMetrics = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
|
|
1042
|
+
_AllureReport_ci = new WeakMap(), _AllureReport_store = new WeakMap(), _AllureReport_readers = new WeakMap(), _AllureReport_plugins = new WeakMap(), _AllureReport_reportFiles = new WeakMap(), _AllureReport_realtimeChannel = new WeakMap(), _AllureReport_realtimeUpdateScheduler = new WeakMap(), _AllureReport_realTime = new WeakMap(), _AllureReport_hideLabels = new WeakMap(), _AllureReport_output = new WeakMap(), _AllureReport_history = new WeakMap(), _AllureReport_appendHistory = new WeakMap(), _AllureReport_allureServiceClient = new WeakMap(), _AllureReport_qualityGate = new WeakMap(), _AllureReport_dump = new WeakMap(), _AllureReport_categories = new WeakMap(), _AllureReport_environments = new WeakMap(), _AllureReport_globalAttachments = new WeakMap(), _AllureReport_knownIssuesPath = new WeakMap(), _AllureReport_dumpTempDirs = new WeakMap(), _AllureReport_cwd = new WeakMap(), _AllureReport_state = new WeakMap(), _AllureReport_executionStage = new WeakMap(), _AllureReport_historyDataPoint = new WeakMap(), _AllureReport_summaryPath = new WeakMap(), _AllureReport_testResultsRegistryPath = new WeakMap(), _AllureReport_summariesByPluginId = new WeakMap(), _AllureReport_publishedRemoteHrefs = new WeakMap(), _AllureReport_artifactFilesByPath = new WeakMap(), _AllureReport_published = new WeakMap(), _AllureReport_endGeneratePerfSpan = new WeakMap(), _AllureReport_createHistoryDataPoint = new WeakMap(), _AllureReport_ingestSelfPerfMetrics = new WeakMap(), _AllureReport_publish = new WeakMap(), _AllureReport_getCwd = new WeakMap(), _AllureReport_runRealtimeUpdate = new WeakMap(), _AllureReport_recordArtifact = new WeakMap(), _AllureReport_restoreStateDumps = new WeakMap(), _AllureReport_getReportsToPublish = new WeakMap(), _AllureReport_cleanupFailedRemoteReport = new WeakMap(), _AllureReport_logPublishError = new WeakMap(), _AllureReport_applyPublishLinksToSummaries = new WeakMap(), _AllureReport_cloneSummariesByPluginId = new WeakMap(), _AllureReport_writeSummaryFiles = new WeakMap(), _AllureReport_writeTestResultRegistry = new WeakMap(), _AllureReport_getRootRemoteReportFiles = new WeakMap(), _AllureReport_writeQualityGateFiles = new WeakMap(), _AllureReport_finishArtifactsManifest = new WeakMap(), _AllureReport_generateRootSummary = new WeakMap(), _AllureReport_finishGeneratePerfSpan = new WeakMap(), _AllureReport_finishPerfMetrics = new WeakMap(), _AllureReport_eachPlugin = new WeakMap(), _AllureReport_instances = new WeakSet(), _AllureReport_getPluginState = function _AllureReport_getPluginState(init, id) {
|
|
969
1043
|
return init ? new DefaultPluginState({}) : __classPrivateFieldGet(this, _AllureReport_state, "f")?.[id];
|
|
970
1044
|
};
|
package/dist/store/store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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";
|
|
1
|
+
import { type AllureCheckResult, type AllureHistory, type AllurePerformanceResult, type AttachmentLink, type DefaultLabelsConfig, type EnvironmentIdentity, type EnvironmentsConfig, type GlobalAttachmentLink, type HistoryDataPoint, type HistoryTestResult, type ResolutionIssue, type ResolutionsConfig, type MetricSample, type PerformanceConfig, type ReportVariables, type Statistic, type TestCase, type TestEnvGroup, type TestError, type TestFixtureResult, type TestResult } from "@allurereport/core-api";
|
|
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>;
|
|
@@ -21,6 +21,7 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
|
|
|
21
21
|
allowedEnvironments?: string[];
|
|
22
22
|
environmentsConfig?: EnvironmentsConfig;
|
|
23
23
|
reportVariables?: ReportVariables;
|
|
24
|
+
performance?: PerformanceConfig;
|
|
24
25
|
});
|
|
25
26
|
readHistory(): Promise<HistoryDataPoint[]>;
|
|
26
27
|
appendHistory(history: HistoryDataPoint): Promise<void>;
|
|
@@ -35,6 +36,7 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
|
|
|
35
36
|
allGlobalAttachments(): Promise<GlobalAttachmentLink[]>;
|
|
36
37
|
allGlobalAttachmentsByEnv(): Promise<Record<string, GlobalAttachmentLink[]>>;
|
|
37
38
|
visitCheckResult(result: AllureCheckResult): Promise<void>;
|
|
39
|
+
visitMetrics(metrics: AllurePerformanceResult[], context?: ReaderContext): Promise<void>;
|
|
38
40
|
visitTestResult(raw: RawTestResult, context: ReaderContext): Promise<void>;
|
|
39
41
|
visitTestFixtureResult(result: RawFixtureResult, context: ReaderContext): Promise<void>;
|
|
40
42
|
visitAttachmentFile(resultFile: ResultFile): Promise<void>;
|
|
@@ -57,6 +59,7 @@ export declare class DefaultAllureStore implements AllureStore, ResultsVisitor {
|
|
|
57
59
|
allResolutionIssues(): Promise<ResolutionIssue[]>;
|
|
58
60
|
resolutionIssueByTestResultId(trId: string): Promise<ResolutionIssue | undefined>;
|
|
59
61
|
testResultsByResolutionIssueId(resolutionIssueId: string): Promise<TestResult[]>;
|
|
62
|
+
allMetrics(): Promise<MetricSample[]>;
|
|
60
63
|
allNewTestResults(filter?: TestResultFilter, history?: HistoryDataPoint[]): Promise<TestResult[]>;
|
|
61
64
|
testCaseById(tcId: string): Promise<TestCase | undefined>;
|
|
62
65
|
testResultById(trId: string): Promise<TestResult | undefined>;
|
package/dist/store/store.js
CHANGED
|
@@ -9,9 +9,9 @@ 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_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;
|
|
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_metrics, _DefaultAllureStore_performance, _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
|
-
import { DEFAULT_ENVIRONMENT, DEFAULT_ENVIRONMENT_IDENTITY, compareBy, createDictionary, getHistoryIdCandidates, getWorstStatus, normalizeHistoryDataPoint, ordinal, reverse, selectHistoryTestResults, validateEnvironmentId, validateEnvironmentName, } from "@allurereport/core-api";
|
|
14
|
+
import { DEFAULT_ENVIRONMENT, DEFAULT_ENVIRONMENT_IDENTITY, compareBy, createDictionary, getHistoryIdCandidates, getWorstStatus, normalizeHistoryDataPoint, ordinal, reverse, resolveMetricSamples, selectHistoryTestResults, validateEnvironmentId, validateEnvironmentName, } from "@allurereport/core-api";
|
|
15
15
|
import { md5, } from "@allurereport/plugin-api";
|
|
16
16
|
import { getResolutionByRules, isIgnoredFailure } from "../resolutions.js";
|
|
17
17
|
import { environmentIdentityById, normalizeEnvironmentDescriptorMap, resolveEnvironmentIdentity, resolveStoredEnvironmentIdentity, validateAllowedEnvironmentId, } from "../utils/environment.js";
|
|
@@ -92,9 +92,11 @@ export class DefaultAllureStore {
|
|
|
92
92
|
_DefaultAllureStore_globalExitCode.set(this, void 0);
|
|
93
93
|
_DefaultAllureStore_checkResultsById.set(this, new Map());
|
|
94
94
|
_DefaultAllureStore_qualityGateResults.set(this, []);
|
|
95
|
+
_DefaultAllureStore_metrics.set(this, []);
|
|
96
|
+
_DefaultAllureStore_performance.set(this, {});
|
|
95
97
|
_DefaultAllureStore_historyPoints.set(this, []);
|
|
96
98
|
_DefaultAllureStore_environments.set(this, []);
|
|
97
|
-
const { history, resolutionsConfig, realtimeDispatcher, realtimeSubscriber, defaultLabels = {}, environment, allowedEnvironments, environmentsConfig = {}, reportVariables = {}, } = params ?? {};
|
|
99
|
+
const { history, resolutionsConfig, realtimeDispatcher, realtimeSubscriber, defaultLabels = {}, environment, allowedEnvironments, environmentsConfig = {}, reportVariables = {}, performance = {}, } = params ?? {};
|
|
98
100
|
const errors = [];
|
|
99
101
|
const { normalized: normalizedEnvironmentsConfig, identities, errors: configErrors, } = normalizeEnvironmentDescriptorMap(environmentsConfig, "environmentsConfig");
|
|
100
102
|
errors.push(...configErrors);
|
|
@@ -120,6 +122,7 @@ export class DefaultAllureStore {
|
|
|
120
122
|
__classPrivateFieldSet(this, _DefaultAllureStore_fixtures, new Map(), "f");
|
|
121
123
|
__classPrivateFieldSet(this, _DefaultAllureStore_history, history, "f");
|
|
122
124
|
__classPrivateFieldSet(this, _DefaultAllureStore_resolutionsConfig, resolutionsConfig, "f");
|
|
125
|
+
__classPrivateFieldSet(this, _DefaultAllureStore_performance, performance, "f");
|
|
123
126
|
__classPrivateFieldSet(this, _DefaultAllureStore_realtimeDispatcher, realtimeDispatcher, "f");
|
|
124
127
|
__classPrivateFieldSet(this, _DefaultAllureStore_realtimeSubscriber, realtimeSubscriber, "f");
|
|
125
128
|
__classPrivateFieldSet(this, _DefaultAllureStore_defaultLabels, defaultLabels, "f");
|
|
@@ -290,6 +293,13 @@ export class DefaultAllureStore {
|
|
|
290
293
|
async visitCheckResult(result) {
|
|
291
294
|
await this.addCheckResult(result);
|
|
292
295
|
}
|
|
296
|
+
async visitMetrics(metrics, context = { readerId: "api" }) {
|
|
297
|
+
const source = context.metadata?.originalFileName;
|
|
298
|
+
__classPrivateFieldGet(this, _DefaultAllureStore_metrics, "f").push(...resolveMetricSamples(metrics.map((metric) => ({
|
|
299
|
+
...metric,
|
|
300
|
+
...(source ? { source } : {}),
|
|
301
|
+
})), __classPrivateFieldGet(this, _DefaultAllureStore_performance, "f")));
|
|
302
|
+
}
|
|
293
303
|
async visitTestResult(raw, context) {
|
|
294
304
|
const attachmentLinks = [];
|
|
295
305
|
const testResult = testResultRawToState({
|
|
@@ -529,6 +539,9 @@ export class DefaultAllureStore {
|
|
|
529
539
|
.map((testResultId) => __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f").get(testResultId))
|
|
530
540
|
.filter(Boolean);
|
|
531
541
|
}
|
|
542
|
+
async allMetrics() {
|
|
543
|
+
return [...__classPrivateFieldGet(this, _DefaultAllureStore_metrics, "f")];
|
|
544
|
+
}
|
|
532
545
|
async allNewTestResults(filter, history) {
|
|
533
546
|
if (!__classPrivateFieldGet(this, _DefaultAllureStore_history, "f") && !history) {
|
|
534
547
|
return [];
|
|
@@ -673,6 +686,20 @@ export class DefaultAllureStore {
|
|
|
673
686
|
}
|
|
674
687
|
async testsStatistic(filter) {
|
|
675
688
|
const statistic = { total: 0 };
|
|
689
|
+
const incrementResolution = (tr) => {
|
|
690
|
+
if (tr.resolution === "issue") {
|
|
691
|
+
statistic.resolutions ?? (statistic.resolutions = {});
|
|
692
|
+
statistic.resolutions.issues = (statistic.resolutions.issues ?? 0) + 1;
|
|
693
|
+
}
|
|
694
|
+
if (tr.resolution === "muted") {
|
|
695
|
+
statistic.resolutions ?? (statistic.resolutions = {});
|
|
696
|
+
statistic.resolutions.muted = (statistic.resolutions.muted ?? 0) + 1;
|
|
697
|
+
}
|
|
698
|
+
if (tr.resolution === "accepted") {
|
|
699
|
+
statistic.resolutions ?? (statistic.resolutions = {});
|
|
700
|
+
statistic.resolutions.accepted = (statistic.resolutions.accepted ?? 0) + 1;
|
|
701
|
+
}
|
|
702
|
+
};
|
|
676
703
|
for (const [, tr] of __classPrivateFieldGet(this, _DefaultAllureStore_testResults, "f")) {
|
|
677
704
|
if (tr.isRetry) {
|
|
678
705
|
continue;
|
|
@@ -691,6 +718,7 @@ export class DefaultAllureStore {
|
|
|
691
718
|
if (tr.transition === "new") {
|
|
692
719
|
statistic.new = (statistic.new ?? 0) + 1;
|
|
693
720
|
}
|
|
721
|
+
incrementResolution(tr);
|
|
694
722
|
if (!statistic[tr.status]) {
|
|
695
723
|
statistic[tr.status] = 0;
|
|
696
724
|
}
|
|
@@ -811,6 +839,7 @@ export class DefaultAllureStore {
|
|
|
811
839
|
indexFixturesByTestResult: {},
|
|
812
840
|
resolutionIssues: mapToObject(__classPrivateFieldGet(this, _DefaultAllureStore_resolutionIssues, "f")),
|
|
813
841
|
qualityGateResults: __classPrivateFieldGet(this, _DefaultAllureStore_qualityGateResults, "f"),
|
|
842
|
+
metrics: __classPrivateFieldGet(this, _DefaultAllureStore_metrics, "f"),
|
|
814
843
|
testResultIdsIngestOrder: __classPrivateFieldGet(this, _DefaultAllureStore_retrySubstore, "f").ingestOrderIdsForDump(),
|
|
815
844
|
};
|
|
816
845
|
this.indexAttachmentByFixture.forEach((link, fxId) => {
|
|
@@ -834,7 +863,7 @@ export class DefaultAllureStore {
|
|
|
834
863
|
return storeDump;
|
|
835
864
|
}
|
|
836
865
|
async restoreState(stateDump, attachmentsContents = {}) {
|
|
837
|
-
const { testResults, attachments, testCases, fixtures, reportVariables, environments, globalAttachmentIds = [], globalErrors = [], checkResults, indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexTestResultByResolutionIssue = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, resolutionIssues = {}, qualityGateResults = [], testResultIdsIngestOrder = [], } = stateDump;
|
|
866
|
+
const { testResults, attachments, testCases, fixtures, reportVariables, environments, globalAttachmentIds = [], globalErrors = [], checkResults, indexAttachmentByTestResult = {}, indexTestResultByHistoryId = {}, indexTestResultByTestCase = {}, indexTestResultByResolutionIssue = {}, indexAttachmentByFixture = {}, indexFixturesByTestResult = {}, resolutionIssues = {}, qualityGateResults = [], metrics = [], testResultIdsIngestOrder = [], } = stateDump;
|
|
838
867
|
const storedEnvironmentAliases = environments.flatMap((environmentValue) => {
|
|
839
868
|
if (typeof environmentValue === "string") {
|
|
840
869
|
return [{ id: environmentValue, name: environmentValue }];
|
|
@@ -1018,9 +1047,10 @@ export class DefaultAllureStore {
|
|
|
1018
1047
|
});
|
|
1019
1048
|
__classPrivateFieldGet(this, _DefaultAllureStore_qualityGateResults, "f").push(result);
|
|
1020
1049
|
});
|
|
1050
|
+
__classPrivateFieldGet(this, _DefaultAllureStore_metrics, "f").push(...metrics);
|
|
1021
1051
|
}
|
|
1022
1052
|
}
|
|
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) {
|
|
1053
|
+
_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_metrics = new WeakMap(), _DefaultAllureStore_performance = new WeakMap(), _DefaultAllureStore_historyPoints = new WeakMap(), _DefaultAllureStore_environments = new WeakMap(), _DefaultAllureStore_instances = new WeakSet(), _DefaultAllureStore_mergeEnvironmentIdentity = function _DefaultAllureStore_mergeEnvironmentIdentity(existingEnvironment, incomingEnvironment) {
|
|
1024
1054
|
const configuredEnvironment = environmentIdentityById(__classPrivateFieldGet(this, _DefaultAllureStore_environmentsConfig, "f"), incomingEnvironment.id);
|
|
1025
1055
|
if (configuredEnvironment) {
|
|
1026
1056
|
return configuredEnvironment;
|
|
@@ -1125,6 +1155,7 @@ _DefaultAllureStore_testResults = new WeakMap(), _DefaultAllureStore_environment
|
|
|
1125
1155
|
}, _DefaultAllureStore_classifyResolution = function _DefaultAllureStore_classifyResolution(testResult) {
|
|
1126
1156
|
const rule = getResolutionByRules(testResult, __classPrivateFieldGet(this, _DefaultAllureStore_resolutionsConfig, "f"));
|
|
1127
1157
|
testResult.resolution = rule?.resolution;
|
|
1158
|
+
testResult.resolutionComment = rule?.comment;
|
|
1128
1159
|
__classPrivateFieldGet(this, _DefaultAllureStore_instances, "m", _DefaultAllureStore_removeResolutionIssueAssociation).call(this, testResult.id);
|
|
1129
1160
|
if (rule?.resolution !== "issue") {
|
|
1130
1161
|
return;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const ARTIFACTS_MANIFEST_FILENAME = "artifacts.json";
|
|
2
|
+
export type ReportArtifact = {
|
|
3
|
+
name: string;
|
|
4
|
+
path: string;
|
|
5
|
+
};
|
|
6
|
+
export type ReportArtifactsManifest = ReportArtifact[];
|
|
7
|
+
export type RestoreStateDumpInput = {
|
|
8
|
+
artifactPath?: string;
|
|
9
|
+
path: string;
|
|
10
|
+
recordArtifact?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare const normalizeArtifactPath: (filePath: string, cwd: string) => string;
|
|
13
|
+
export declare const createReportArtifact: (filePath: string, cwd: string, name?: string) => ReportArtifact;
|
|
14
|
+
export declare const deduplicateDumpInputs: (dumps: RestoreStateDumpInput[], cwd: string) => RestoreStateDumpInput[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { basename, relative, resolve, sep } from "node:path";
|
|
3
|
+
export const ARTIFACTS_MANIFEST_FILENAME = "artifacts.json";
|
|
4
|
+
const existingRealPath = (filePath) => {
|
|
5
|
+
try {
|
|
6
|
+
return realpathSync(filePath);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return filePath;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export const normalizeArtifactPath = (filePath, cwd) => {
|
|
13
|
+
const path = relative(resolve(cwd), resolve(cwd, filePath)).split(sep).join("/");
|
|
14
|
+
return path || ".";
|
|
15
|
+
};
|
|
16
|
+
export const createReportArtifact = (filePath, cwd, name = basename(filePath)) => ({
|
|
17
|
+
name,
|
|
18
|
+
path: normalizeArtifactPath(filePath, cwd),
|
|
19
|
+
});
|
|
20
|
+
export const deduplicateDumpInputs = (dumps, cwd) => {
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
return dumps.reduce((acc, dump) => {
|
|
23
|
+
const absolutePath = resolve(cwd, dump.path);
|
|
24
|
+
const dedupeKey = existingRealPath(absolutePath);
|
|
25
|
+
if (seen.has(dedupeKey)) {
|
|
26
|
+
return acc;
|
|
27
|
+
}
|
|
28
|
+
seen.add(dedupeKey);
|
|
29
|
+
acc.push({
|
|
30
|
+
...dump,
|
|
31
|
+
path: absolutePath,
|
|
32
|
+
});
|
|
33
|
+
return acc;
|
|
34
|
+
}, []);
|
|
35
|
+
};
|
package/dist/utils/perf.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { AllurePerformanceResult } from "@allurereport/core-api";
|
|
2
|
+
export declare const PERF_METRICS_FILE = "performance.json";
|
|
3
|
+
export declare const perfMetricsFileName: (reportUuid: string) => string;
|
|
2
4
|
export type PerfMetricSpan = {
|
|
3
5
|
name: string;
|
|
4
6
|
startTimeMs: number;
|
|
@@ -12,14 +14,8 @@ export type PerfMetricSummary = {
|
|
|
12
14
|
maxMs: number;
|
|
13
15
|
avgMs: number;
|
|
14
16
|
};
|
|
15
|
-
export type PerfMetricsPayload = {
|
|
16
|
-
version: 1;
|
|
17
|
-
generatedAt: string;
|
|
18
|
-
timeOriginMs: number;
|
|
19
|
-
spans: PerfMetricSpan[];
|
|
20
|
-
summary: PerfMetricSummary[];
|
|
21
|
-
};
|
|
22
17
|
export declare const PERF_METRIC_NAMES: {
|
|
18
|
+
readonly allureTotal: "allure.total";
|
|
23
19
|
readonly restoreStateTotal: "restoreState.total";
|
|
24
20
|
readonly restoreStateDump: "restoreState.dump";
|
|
25
21
|
readonly restoreStateAttachments: "restoreState.attachments";
|
|
@@ -37,6 +33,6 @@ export declare const PERF_METRIC_PREFIXES: {
|
|
|
37
33
|
export declare const isPerfMetricsEnabled: () => boolean;
|
|
38
34
|
export declare const startPerfSpan: (name: string) => (() => void);
|
|
39
35
|
export declare const measurePerf: <T>(name: string, fn: () => Promise<T>) => Promise<T>;
|
|
40
|
-
export declare const
|
|
41
|
-
export declare const writePerfMetrics: (output: string) => Promise<boolean>;
|
|
36
|
+
export declare const getPerfMetricsResults: () => AllurePerformanceResult[];
|
|
37
|
+
export declare const writePerfMetrics: (output: string, fileName?: string) => Promise<boolean>;
|
|
42
38
|
export declare const resetPerfMetrics: () => void;
|
package/dist/utils/perf.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import { performance } from "node:perf_hooks";
|
|
4
|
-
export const PERF_METRICS_FILE = "
|
|
5
|
+
export const PERF_METRICS_FILE = "performance.json";
|
|
6
|
+
export const perfMetricsFileName = (reportUuid) => `${reportUuid}-perf.json`;
|
|
5
7
|
const MARK_PREFIX = "allure:perf:";
|
|
6
8
|
const ENABLED_VALUES = new Set(["1", "true", "yes", "on"]);
|
|
7
9
|
const SPANS = [];
|
|
@@ -10,6 +12,7 @@ const MEASURES = new Set();
|
|
|
10
12
|
let sequence = 0;
|
|
11
13
|
const round = (value) => Number(value.toFixed(3));
|
|
12
14
|
export const PERF_METRIC_NAMES = {
|
|
15
|
+
allureTotal: "allure.total",
|
|
13
16
|
restoreStateTotal: "restoreState.total",
|
|
14
17
|
restoreStateDump: "restoreState.dump",
|
|
15
18
|
restoreStateAttachments: "restoreState.attachments",
|
|
@@ -24,6 +27,22 @@ export const PERF_METRIC_PREFIXES = {
|
|
|
24
27
|
generatePluginDone: "generate.plugin.done.",
|
|
25
28
|
publishUploadPlugin: "publish.upload.plugin.",
|
|
26
29
|
};
|
|
30
|
+
const getCoveredDurationSummary = () => {
|
|
31
|
+
if (SPANS.length === 0) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
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);
|
|
37
|
+
return {
|
|
38
|
+
name: PERF_METRIC_NAMES.allureTotal,
|
|
39
|
+
count: 1,
|
|
40
|
+
totalMs: durationMs,
|
|
41
|
+
minMs: durationMs,
|
|
42
|
+
maxMs: durationMs,
|
|
43
|
+
avgMs: durationMs,
|
|
44
|
+
};
|
|
45
|
+
};
|
|
27
46
|
export const isPerfMetricsEnabled = () => ENABLED_VALUES.has((process.env.ALLURE_PERF_METRICS ?? "").toLowerCase());
|
|
28
47
|
export const startPerfSpan = (name) => {
|
|
29
48
|
if (!isPerfMetricsEnabled()) {
|
|
@@ -72,39 +91,33 @@ export const measurePerf = async (name, fn) => {
|
|
|
72
91
|
end();
|
|
73
92
|
}
|
|
74
93
|
};
|
|
75
|
-
export const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
94
|
+
export const getPerfMetricsResults = () => {
|
|
95
|
+
const totalSummary = getCoveredDurationSummary();
|
|
96
|
+
const results = SPANS.map((span) => ({
|
|
97
|
+
id: randomUUID(),
|
|
98
|
+
key: span.name,
|
|
99
|
+
value: span.durationMs,
|
|
100
|
+
start: round(performance.timeOrigin + span.startTimeMs),
|
|
101
|
+
stop: round(performance.timeOrigin + span.startTimeMs + span.durationMs),
|
|
102
|
+
}));
|
|
103
|
+
if (totalSummary) {
|
|
104
|
+
results.unshift({
|
|
105
|
+
id: randomUUID(),
|
|
106
|
+
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))),
|
|
110
|
+
});
|
|
81
111
|
}
|
|
82
|
-
return
|
|
83
|
-
version: 1,
|
|
84
|
-
generatedAt: new Date().toISOString(),
|
|
85
|
-
timeOriginMs: round(performance.timeOrigin),
|
|
86
|
-
spans: [...SPANS],
|
|
87
|
-
summary: [...byName.entries()].map(([name, group]) => {
|
|
88
|
-
const durations = group.map(({ durationMs }) => durationMs);
|
|
89
|
-
const totalMs = durations.reduce((acc, duration) => acc + duration, 0);
|
|
90
|
-
return {
|
|
91
|
-
name,
|
|
92
|
-
count: group.length,
|
|
93
|
-
totalMs: round(totalMs),
|
|
94
|
-
minMs: round(Math.min(...durations)),
|
|
95
|
-
maxMs: round(Math.max(...durations)),
|
|
96
|
-
avgMs: round(totalMs / group.length),
|
|
97
|
-
};
|
|
98
|
-
}),
|
|
99
|
-
};
|
|
112
|
+
return results;
|
|
100
113
|
};
|
|
101
|
-
export const writePerfMetrics = async (output) => {
|
|
114
|
+
export const writePerfMetrics = async (output, fileName = PERF_METRICS_FILE) => {
|
|
102
115
|
if (!isPerfMetricsEnabled()) {
|
|
103
116
|
return false;
|
|
104
117
|
}
|
|
105
|
-
const
|
|
118
|
+
const results = getPerfMetricsResults();
|
|
106
119
|
await mkdir(output, { recursive: true });
|
|
107
|
-
await writeFile(join(output,
|
|
120
|
+
await writeFile(join(output, fileName), `${JSON.stringify(results, null, 2)}\n`, "utf8");
|
|
108
121
|
resetPerfMetrics();
|
|
109
122
|
return true;
|
|
110
123
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allurereport/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.17.0",
|
|
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.
|
|
29
|
-
"@allurereport/cli-commons": "3.
|
|
30
|
-
"@allurereport/core-api": "3.
|
|
31
|
-
"@allurereport/plugin-agent": "3.
|
|
32
|
-
"@allurereport/plugin-allure2": "3.
|
|
33
|
-
"@allurereport/plugin-api": "3.
|
|
34
|
-
"@allurereport/plugin-awesome": "3.
|
|
35
|
-
"@allurereport/plugin-classic": "3.
|
|
36
|
-
"@allurereport/plugin-csv": "3.
|
|
37
|
-
"@allurereport/plugin-dashboard": "3.
|
|
38
|
-
"@allurereport/plugin-jira": "3.
|
|
39
|
-
"@allurereport/plugin-log": "3.
|
|
40
|
-
"@allurereport/plugin-progress": "3.
|
|
41
|
-
"@allurereport/plugin-slack": "3.
|
|
42
|
-
"@allurereport/plugin-testops": "3.
|
|
43
|
-
"@allurereport/plugin-testplan": "3.
|
|
44
|
-
"@allurereport/reader": "3.
|
|
45
|
-
"@allurereport/reader-api": "3.
|
|
46
|
-
"@allurereport/service": "3.
|
|
47
|
-
"@allurereport/summary": "3.
|
|
28
|
+
"@allurereport/ci": "3.17.0",
|
|
29
|
+
"@allurereport/cli-commons": "3.17.0",
|
|
30
|
+
"@allurereport/core-api": "3.17.0",
|
|
31
|
+
"@allurereport/plugin-agent": "3.17.0",
|
|
32
|
+
"@allurereport/plugin-allure2": "3.17.0",
|
|
33
|
+
"@allurereport/plugin-api": "3.17.0",
|
|
34
|
+
"@allurereport/plugin-awesome": "3.17.0",
|
|
35
|
+
"@allurereport/plugin-classic": "3.17.0",
|
|
36
|
+
"@allurereport/plugin-csv": "3.17.0",
|
|
37
|
+
"@allurereport/plugin-dashboard": "3.17.0",
|
|
38
|
+
"@allurereport/plugin-jira": "3.17.0",
|
|
39
|
+
"@allurereport/plugin-log": "3.17.0",
|
|
40
|
+
"@allurereport/plugin-progress": "3.17.0",
|
|
41
|
+
"@allurereport/plugin-slack": "3.17.0",
|
|
42
|
+
"@allurereport/plugin-testops": "3.17.0",
|
|
43
|
+
"@allurereport/plugin-testplan": "3.17.0",
|
|
44
|
+
"@allurereport/reader": "3.17.0",
|
|
45
|
+
"@allurereport/reader-api": "3.17.0",
|
|
46
|
+
"@allurereport/service": "3.17.0",
|
|
47
|
+
"@allurereport/summary": "3.17.0",
|
|
48
48
|
"glob": "^13.0.6",
|
|
49
49
|
"handlebars": "^4.7.9",
|
|
50
50
|
"jiti": "^2.5.1",
|