@allurereport/core 3.2.0 → 3.4.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 +4 -2
- package/dist/config.d.ts +2 -0
- package/dist/config.js +73 -6
- package/dist/history.d.ts +1 -1
- package/dist/history.js +39 -15
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/plugin.js +2 -1
- package/dist/qualityGate/qualityGate.js +2 -2
- package/dist/qualityGate/rules.d.ts +3 -1
- package/dist/qualityGate/rules.js +40 -6
- package/dist/report.d.ts +1 -1
- package/dist/report.js +71 -48
- package/dist/store/convert.js +1 -1
- package/dist/store/store.d.ts +16 -5
- package/dist/store/store.js +376 -72
- package/dist/utils/environment.d.ts +24 -0
- package/dist/utils/environment.js +160 -0
- package/dist/utils/event.d.ts +1 -1
- package/dist/utils/safeDumpPath.d.ts +4 -0
- package/dist/utils/safeDumpPath.js +22 -0
- package/dist/utils/safeOutputPath.d.ts +5 -0
- package/dist/utils/safeOutputPath.js +31 -0
- package/dist/utils/windows.d.ts +2 -0
- package/dist/utils/windows.js +51 -0
- package/package.json +30 -42
package/dist/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DefaultLabelsConfig, EnvironmentsConfig, KnownTestFailure, ReportVariables } from "@allurereport/core-api";
|
|
1
|
+
import type { CategoriesConfig, DefaultLabelsConfig, EnvironmentsConfig, KnownTestFailure, ReportVariables } from "@allurereport/core-api";
|
|
2
2
|
import type { Plugin, QualityGateConfig, ReportFiles } from "@allurereport/plugin-api";
|
|
3
3
|
import type { ResultsReader } from "@allurereport/reader-api";
|
|
4
4
|
export interface PluginInstance {
|
|
@@ -12,11 +12,12 @@ export interface FullConfig {
|
|
|
12
12
|
output: string;
|
|
13
13
|
open: boolean;
|
|
14
14
|
port: string | undefined;
|
|
15
|
+
hideLabels?: (string | RegExp)[];
|
|
15
16
|
historyPath?: string;
|
|
16
17
|
historyLimit?: number;
|
|
17
18
|
knownIssuesPath: string;
|
|
18
19
|
defaultLabels?: DefaultLabelsConfig;
|
|
19
|
-
|
|
20
|
+
dump?: string;
|
|
20
21
|
environment?: string;
|
|
21
22
|
environments?: EnvironmentsConfig;
|
|
22
23
|
variables?: ReportVariables;
|
|
@@ -27,6 +28,7 @@ export interface FullConfig {
|
|
|
27
28
|
known?: KnownTestFailure[];
|
|
28
29
|
realTime?: any;
|
|
29
30
|
qualityGate?: QualityGateConfig;
|
|
31
|
+
categories?: CategoriesConfig;
|
|
30
32
|
allureService?: {
|
|
31
33
|
accessToken?: string;
|
|
32
34
|
};
|
package/dist/config.d.ts
CHANGED
|
@@ -5,11 +5,13 @@ export interface ConfigOverride {
|
|
|
5
5
|
output?: Config["output"];
|
|
6
6
|
open?: Config["open"];
|
|
7
7
|
port?: Config["port"];
|
|
8
|
+
hideLabels?: Config["hideLabels"];
|
|
8
9
|
historyPath?: Config["historyPath"];
|
|
9
10
|
historyLimit?: Config["historyLimit"];
|
|
10
11
|
knownIssuesPath?: Config["knownIssuesPath"];
|
|
11
12
|
plugins?: Config["plugins"];
|
|
12
13
|
}
|
|
14
|
+
export declare const assertValidPluginId: (id: string) => void;
|
|
13
15
|
export declare const getPluginId: (key: string) => string;
|
|
14
16
|
export declare const findConfig: (cwd: string, configPath?: string) => Promise<string | undefined>;
|
|
15
17
|
export declare const validateConfig: (config: Config) => {
|
package/dist/config.js
CHANGED
|
@@ -2,11 +2,14 @@ import * as console from "node:console";
|
|
|
2
2
|
import { readFile, stat } from "node:fs/promises";
|
|
3
3
|
import { extname, resolve } from "node:path";
|
|
4
4
|
import * as process from "node:process";
|
|
5
|
+
import { validateEnvironmentName } from "@allurereport/core-api";
|
|
5
6
|
import { parse } from "yaml";
|
|
6
7
|
import { readKnownIssues } from "./known.js";
|
|
7
8
|
import { FileSystemReportFiles } from "./plugin.js";
|
|
9
|
+
import { environmentIdentityById, environmentIdentityByName, normalizeEnvironmentDescriptorMap, } from "./utils/environment.js";
|
|
8
10
|
import { importWrapper } from "./utils/module.js";
|
|
9
11
|
import { normalizeImportPath } from "./utils/path.js";
|
|
12
|
+
import { assertValidPluginIdForWindows, isWindows } from "./utils/windows.js";
|
|
10
13
|
const CONFIG_FILENAMES = [
|
|
11
14
|
"allurerc.js",
|
|
12
15
|
"allurerc.mjs",
|
|
@@ -16,8 +19,31 @@ const CONFIG_FILENAMES = [
|
|
|
16
19
|
"allurerc.yml",
|
|
17
20
|
];
|
|
18
21
|
const DEFAULT_CONFIG = {};
|
|
22
|
+
export const assertValidPluginId = (id) => {
|
|
23
|
+
if (id.length === 0) {
|
|
24
|
+
throw new Error("Invalid plugin id: must not be empty");
|
|
25
|
+
}
|
|
26
|
+
if (id === "." || id === "..") {
|
|
27
|
+
throw new Error(`Invalid plugin id ${JSON.stringify(id)}: must not be "." or ".."`);
|
|
28
|
+
}
|
|
29
|
+
if (id.includes("..")) {
|
|
30
|
+
throw new Error(`Invalid plugin id ${JSON.stringify(id)}: must not contain ".."`);
|
|
31
|
+
}
|
|
32
|
+
if (/[/\\]/.test(id)) {
|
|
33
|
+
throw new Error(`Invalid plugin id ${JSON.stringify(id)}: must not contain path separators`);
|
|
34
|
+
}
|
|
35
|
+
if (isWindows()) {
|
|
36
|
+
assertValidPluginIdForWindows(id);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
19
39
|
export const getPluginId = (key) => {
|
|
20
|
-
|
|
40
|
+
const trimmed = key.trim();
|
|
41
|
+
if (trimmed.length === 0) {
|
|
42
|
+
throw new Error(`Invalid plugin key ${JSON.stringify(key)}: must not be empty or whitespace-only`);
|
|
43
|
+
}
|
|
44
|
+
const id = trimmed.replace(/^@.*\//, "").replace(/[/\\]/g, "-");
|
|
45
|
+
assertValidPluginId(id);
|
|
46
|
+
return id;
|
|
21
47
|
};
|
|
22
48
|
export const findConfig = async (cwd, configPath) => {
|
|
23
49
|
if (configPath) {
|
|
@@ -51,16 +77,19 @@ export const validateConfig = (config) => {
|
|
|
51
77
|
"output",
|
|
52
78
|
"open",
|
|
53
79
|
"port",
|
|
80
|
+
"hideLabels",
|
|
54
81
|
"historyPath",
|
|
55
82
|
"historyLimit",
|
|
56
83
|
"knownIssuesPath",
|
|
57
84
|
"plugins",
|
|
58
85
|
"defaultLabels",
|
|
59
86
|
"variables",
|
|
87
|
+
"environment",
|
|
60
88
|
"environments",
|
|
61
89
|
"appendHistory",
|
|
62
90
|
"qualityGate",
|
|
63
91
|
"allureService",
|
|
92
|
+
"categories",
|
|
64
93
|
];
|
|
65
94
|
const unsupportedFields = Object.keys(config).filter((key) => !supportedFields.includes(key));
|
|
66
95
|
return {
|
|
@@ -97,14 +126,42 @@ export const loadJsonConfig = async (configPath) => {
|
|
|
97
126
|
export const loadJsConfig = async (configPath) => {
|
|
98
127
|
return (await import(normalizeImportPath(configPath))).default;
|
|
99
128
|
};
|
|
129
|
+
const resolveConfigEnvironments = (config) => {
|
|
130
|
+
const errors = [];
|
|
131
|
+
const { normalized: environments, errors: environmentErrors } = normalizeEnvironmentDescriptorMap(config.environments ?? {}, "config.environments");
|
|
132
|
+
let environment;
|
|
133
|
+
errors.push(...environmentErrors);
|
|
134
|
+
if (config.environment !== undefined) {
|
|
135
|
+
const environmentResult = validateEnvironmentName(config.environment);
|
|
136
|
+
if (!environmentResult.valid) {
|
|
137
|
+
errors.push(`environment ${environmentResult.reason}`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const normalizedEnvironment = environmentResult.normalized;
|
|
141
|
+
environment =
|
|
142
|
+
environmentIdentityById(environments, normalizedEnvironment)?.id ??
|
|
143
|
+
environmentIdentityByName(environments, normalizedEnvironment)?.id ??
|
|
144
|
+
normalizedEnvironment;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (errors.length > 0) {
|
|
148
|
+
throw new Error(`The provided Allure config contains invalid environments: ${errors.join("; ")}`);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
environments,
|
|
152
|
+
environment,
|
|
153
|
+
};
|
|
154
|
+
};
|
|
100
155
|
export const resolveConfig = async (config, override = {}) => {
|
|
101
156
|
const validationResult = validateConfig(config);
|
|
102
157
|
if (!validationResult.valid) {
|
|
103
158
|
throw new Error(`The provided Allure config contains unsupported fields: ${validationResult.fields.join(", ")}`);
|
|
104
159
|
}
|
|
160
|
+
const { environments, environment } = resolveConfigEnvironments(config);
|
|
105
161
|
const name = override.name ?? config.name ?? "Allure Report";
|
|
106
162
|
const open = override.open ?? config.open ?? false;
|
|
107
163
|
const port = override.port ?? config.port ?? undefined;
|
|
164
|
+
const hideLabels = override.hideLabels ?? config.hideLabels;
|
|
108
165
|
const historyPath = override.historyPath ?? config.historyPath;
|
|
109
166
|
const historyLimit = override.historyLimit ?? config.historyLimit;
|
|
110
167
|
const appendHistory = config.appendHistory ?? true;
|
|
@@ -112,22 +169,24 @@ export const resolveConfig = async (config, override = {}) => {
|
|
|
112
169
|
const output = resolve(override.output ?? config.output ?? "./allure-report");
|
|
113
170
|
const known = await readKnownIssues(knownIssuesPath);
|
|
114
171
|
const variables = config.variables ?? {};
|
|
115
|
-
const
|
|
116
|
-
const plugins = Object.keys(
|
|
172
|
+
const configuredPlugins = override.plugins ?? config.plugins;
|
|
173
|
+
const plugins = Object.keys(configuredPlugins ?? {}).length === 0
|
|
117
174
|
? {
|
|
118
175
|
awesome: {
|
|
119
176
|
options: {},
|
|
120
177
|
},
|
|
121
178
|
}
|
|
122
|
-
:
|
|
179
|
+
: configuredPlugins;
|
|
123
180
|
const pluginInstances = await resolvePlugins(plugins);
|
|
124
181
|
return {
|
|
125
182
|
name,
|
|
126
183
|
output,
|
|
127
184
|
open,
|
|
128
185
|
port,
|
|
186
|
+
hideLabels,
|
|
129
187
|
knownIssuesPath,
|
|
130
188
|
known,
|
|
189
|
+
environment,
|
|
131
190
|
variables,
|
|
132
191
|
environments,
|
|
133
192
|
appendHistory,
|
|
@@ -138,6 +197,7 @@ export const resolveConfig = async (config, override = {}) => {
|
|
|
138
197
|
defaultLabels: config.defaultLabels ?? {},
|
|
139
198
|
qualityGate: config.qualityGate,
|
|
140
199
|
allureService: config.allureService,
|
|
200
|
+
categories: config.categories,
|
|
141
201
|
};
|
|
142
202
|
};
|
|
143
203
|
export const readConfig = async (cwd = process.cwd(), configPath, override) => {
|
|
@@ -165,19 +225,26 @@ export const readConfig = async (cwd = process.cwd(), configPath, override) => {
|
|
|
165
225
|
export const getPluginInstance = (config, predicate) => {
|
|
166
226
|
return config?.plugins?.find(predicate);
|
|
167
227
|
};
|
|
228
|
+
const isModuleNotFoundError = (err) => {
|
|
229
|
+
return err instanceof Error && "code" in err && err.code === "ERR_MODULE_NOT_FOUND";
|
|
230
|
+
};
|
|
168
231
|
export const resolvePlugin = async (path) => {
|
|
169
232
|
if (!path.startsWith("@allurereport/plugin-")) {
|
|
170
233
|
try {
|
|
171
234
|
const module = await importWrapper(`@allurereport/plugin-${path}`);
|
|
172
235
|
return module.default;
|
|
173
236
|
}
|
|
174
|
-
catch (err) {
|
|
237
|
+
catch (err) {
|
|
238
|
+
if (!isModuleNotFoundError(err)) {
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
175
242
|
}
|
|
176
243
|
try {
|
|
177
244
|
const module = await importWrapper(path);
|
|
178
245
|
return module.default;
|
|
179
246
|
}
|
|
180
|
-
catch
|
|
247
|
+
catch {
|
|
181
248
|
throw new Error(`Cannot resolve plugin: ${path}`);
|
|
182
249
|
}
|
|
183
250
|
};
|
package/dist/history.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AllureHistory, type HistoryDataPoint, type TestCase, type TestResult } from "@allurereport/core-api";
|
|
2
2
|
export declare const createHistory: (reportUuid: string, reportName: string | undefined, testCases: TestCase[], testResults: TestResult[], remoteUrl?: string) => HistoryDataPoint;
|
|
3
3
|
export declare class AllureLocalHistory implements AllureHistory {
|
|
4
4
|
#private;
|
package/dist/history.js
CHANGED
|
@@ -3,14 +3,21 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
3
3
|
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");
|
|
4
4
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
5
|
};
|
|
6
|
-
var
|
|
6
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
|
+
};
|
|
12
|
+
var _AllureLocalHistory_cachedHistory, _AllureLocalHistory_openFileToReadIfExists, _AllureLocalHistory_ensureFileOpenedToAppend, _AllureLocalHistory_findFirstEntryAddress, _AllureLocalHistory_throwUnexpectedReadError;
|
|
7
13
|
import { once } from "node:events";
|
|
8
14
|
import { mkdir, open } from "node:fs/promises";
|
|
9
15
|
import path from "node:path";
|
|
10
16
|
import readline from "node:readline/promises";
|
|
11
17
|
import { pipeline } from "node:stream/promises";
|
|
18
|
+
import { normalizeHistoryDataPointUrls, } from "@allurereport/core-api";
|
|
12
19
|
import { isFileNotFoundError } from "./utils/misc.js";
|
|
13
|
-
const createHistoryItems = (testResults) => {
|
|
20
|
+
const createHistoryItems = (testResults, remoteUrl) => {
|
|
14
21
|
return testResults
|
|
15
22
|
.filter((tr) => tr.historyId)
|
|
16
23
|
.map(({ id, name, fullName, environment, historyId, status, error: { message, trace } = {}, start, stop, duration, labels, }) => {
|
|
@@ -26,7 +33,7 @@ const createHistoryItems = (testResults) => {
|
|
|
26
33
|
stop,
|
|
27
34
|
duration,
|
|
28
35
|
labels,
|
|
29
|
-
url:
|
|
36
|
+
url: remoteUrl,
|
|
30
37
|
historyId: historyId,
|
|
31
38
|
reportLinks: [],
|
|
32
39
|
};
|
|
@@ -43,7 +50,7 @@ export const createHistory = (reportUuid, reportName = "Allure Report", testCase
|
|
|
43
50
|
name: reportName,
|
|
44
51
|
timestamp: new Date().getTime(),
|
|
45
52
|
knownTestCaseIds,
|
|
46
|
-
testResults: createHistoryItems(testResults),
|
|
53
|
+
testResults: createHistoryItems(testResults, remoteUrl),
|
|
47
54
|
metrics: {},
|
|
48
55
|
url: remoteUrl,
|
|
49
56
|
};
|
|
@@ -51,6 +58,7 @@ export const createHistory = (reportUuid, reportName = "Allure Report", testCase
|
|
|
51
58
|
export class AllureLocalHistory {
|
|
52
59
|
constructor(params) {
|
|
53
60
|
this.params = params;
|
|
61
|
+
_AllureLocalHistory_cachedHistory.set(this, []);
|
|
54
62
|
_AllureLocalHistory_openFileToReadIfExists.set(this, async (filePath) => {
|
|
55
63
|
try {
|
|
56
64
|
return await open(filePath, "r");
|
|
@@ -121,6 +129,9 @@ export class AllureLocalHistory {
|
|
|
121
129
|
});
|
|
122
130
|
}
|
|
123
131
|
async readHistory() {
|
|
132
|
+
if (__classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f").length > 0) {
|
|
133
|
+
return __classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f");
|
|
134
|
+
}
|
|
124
135
|
const fullPath = path.resolve(this.params.historyPath);
|
|
125
136
|
const historyFile = await __classPrivateFieldGet(this, _AllureLocalHistory_openFileToReadIfExists, "f").call(this, fullPath);
|
|
126
137
|
if (historyFile === undefined) {
|
|
@@ -134,18 +145,20 @@ export class AllureLocalHistory {
|
|
|
134
145
|
.createInterface({ input: stream, terminal: false, crlfDelay: Infinity })
|
|
135
146
|
.on("line", (line) => {
|
|
136
147
|
if (line && line.trim().length) {
|
|
137
|
-
const historyEntry = JSON.parse(line);
|
|
148
|
+
const historyEntry = normalizeHistoryDataPointUrls(JSON.parse(line));
|
|
138
149
|
historyPoints.push(historyEntry);
|
|
139
150
|
}
|
|
140
151
|
});
|
|
141
152
|
await once(readlineInterface, "close");
|
|
142
|
-
|
|
153
|
+
__classPrivateFieldSet(this, _AllureLocalHistory_cachedHistory, historyPoints, "f");
|
|
154
|
+
return __classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f");
|
|
143
155
|
}
|
|
144
156
|
finally {
|
|
145
157
|
await historyFile.close();
|
|
146
158
|
}
|
|
147
159
|
}
|
|
148
160
|
async appendHistory(data) {
|
|
161
|
+
const normalizedData = normalizeHistoryDataPointUrls(data);
|
|
149
162
|
const fullPath = path.resolve(this.params.historyPath);
|
|
150
163
|
const parentDir = path.dirname(fullPath);
|
|
151
164
|
const { limit } = this.params;
|
|
@@ -153,22 +166,33 @@ export class AllureLocalHistory {
|
|
|
153
166
|
const { file: historyFile, exists: historyExists } = await __classPrivateFieldGet(this, _AllureLocalHistory_ensureFileOpenedToAppend, "f").call(this, fullPath);
|
|
154
167
|
try {
|
|
155
168
|
const dst = historyFile.createWriteStream({ encoding: "utf-8", start: 0, autoClose: false });
|
|
156
|
-
if (limit
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const sources = [JSON.stringify(data), Buffer.from([0x0a])];
|
|
163
|
-
await pipeline(sources, dst);
|
|
169
|
+
if (limit === 0 && historyExists) {
|
|
170
|
+
await historyFile.truncate(0);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (limit === 0 && !historyExists) {
|
|
174
|
+
return;
|
|
164
175
|
}
|
|
176
|
+
if (historyExists) {
|
|
177
|
+
const start = await __classPrivateFieldGet(this, _AllureLocalHistory_findFirstEntryAddress, "f").call(this, historyFile, limit ? limit - 1 : undefined);
|
|
178
|
+
const src = historyFile.createReadStream({ start, autoClose: false });
|
|
179
|
+
await pipeline(src, dst, { end: false });
|
|
180
|
+
}
|
|
181
|
+
const sources = [JSON.stringify(normalizedData), Buffer.from([0x0a])];
|
|
182
|
+
await pipeline(sources, dst);
|
|
165
183
|
if (historyExists) {
|
|
166
184
|
await historyFile.truncate(dst.bytesWritten);
|
|
167
185
|
}
|
|
168
186
|
}
|
|
169
187
|
finally {
|
|
170
188
|
await historyFile.close();
|
|
189
|
+
if (limit !== 0) {
|
|
190
|
+
__classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f").push(normalizedData);
|
|
191
|
+
}
|
|
192
|
+
if (limit) {
|
|
193
|
+
__classPrivateFieldGet(this, _AllureLocalHistory_cachedHistory, "f").splice(limit);
|
|
194
|
+
}
|
|
171
195
|
}
|
|
172
196
|
}
|
|
173
197
|
}
|
|
174
|
-
_AllureLocalHistory_openFileToReadIfExists = new WeakMap(), _AllureLocalHistory_ensureFileOpenedToAppend = new WeakMap(), _AllureLocalHistory_findFirstEntryAddress = new WeakMap(), _AllureLocalHistory_throwUnexpectedReadError = new WeakMap();
|
|
198
|
+
_AllureLocalHistory_cachedHistory = new WeakMap(), _AllureLocalHistory_openFileToReadIfExists = new WeakMap(), _AllureLocalHistory_ensureFileOpenedToAppend = new WeakMap(), _AllureLocalHistory_findFirstEntryAddress = new WeakMap(), _AllureLocalHistory_throwUnexpectedReadError = new WeakMap();
|
package/dist/index.d.ts
CHANGED
|
@@ -4,9 +4,10 @@ export * from "./utils/crypto.js";
|
|
|
4
4
|
export * from "./utils/path.js";
|
|
5
5
|
export * from "./utils/new.js";
|
|
6
6
|
export * from "./utils/flaky.js";
|
|
7
|
+
export * from "./utils/environment.js";
|
|
7
8
|
export * from "./history.js";
|
|
8
9
|
export * from "./known.js";
|
|
9
10
|
export { resolveConfig, readConfig, getPluginInstance } from "./config.js";
|
|
10
11
|
export * from "./report.js";
|
|
11
12
|
export * from "./plugin.js";
|
|
12
|
-
export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
|
|
13
|
+
export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
|
package/dist/index.js
CHANGED
|
@@ -3,9 +3,10 @@ export * from "./utils/crypto.js";
|
|
|
3
3
|
export * from "./utils/path.js";
|
|
4
4
|
export * from "./utils/new.js";
|
|
5
5
|
export * from "./utils/flaky.js";
|
|
6
|
+
export * from "./utils/environment.js";
|
|
6
7
|
export * from "./history.js";
|
|
7
8
|
export * from "./known.js";
|
|
8
9
|
export { resolveConfig, readConfig, getPluginInstance } from "./config.js";
|
|
9
10
|
export * from "./report.js";
|
|
10
11
|
export * from "./plugin.js";
|
|
11
|
-
export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
|
|
12
|
+
export { QualityGateState, qualityGateDefaultRules, maxFailuresRule, minTestsCountRule, successRateRule, maxDurationRule, allTestsContainEnvRule, environmentsTestedRule, convertQualityGateResultsToTestErrors, stringifyQualityGateResults, } from "./qualityGate/index.js";
|
package/dist/plugin.js
CHANGED
|
@@ -13,6 +13,7 @@ var _DefaultPluginState_state, _PluginFiles_parent, _PluginFiles_pluginId, _InMe
|
|
|
13
13
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
14
14
|
import { dirname, resolve } from "node:path";
|
|
15
15
|
import { join as joinPosix } from "node:path/posix";
|
|
16
|
+
import { resolvePathUnderOutputRoot } from "./utils/safeOutputPath.js";
|
|
16
17
|
export class DefaultPluginState {
|
|
17
18
|
constructor(state) {
|
|
18
19
|
_DefaultPluginState_state.set(this, void 0);
|
|
@@ -58,7 +59,7 @@ export class FileSystemReportFiles {
|
|
|
58
59
|
constructor(output) {
|
|
59
60
|
_FileSystemReportFiles_output.set(this, void 0);
|
|
60
61
|
this.addFile = async (path, data) => {
|
|
61
|
-
const targetPath =
|
|
62
|
+
const targetPath = resolvePathUnderOutputRoot(__classPrivateFieldGet(this, _FileSystemReportFiles_output, "f"), path);
|
|
62
63
|
const targetDirPath = dirname(targetPath);
|
|
63
64
|
await mkdir(targetDirPath, { recursive: true });
|
|
64
65
|
await writeFile(targetPath, data, { encoding: "utf-8" });
|
|
@@ -4,7 +4,6 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
4
4
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
5
|
};
|
|
6
6
|
var _QualityGateState_state;
|
|
7
|
-
import { DEFAULT_ENVIRONMENT } from "@allurereport/core-api";
|
|
8
7
|
import { gray, red } from "yoctocolors";
|
|
9
8
|
import { qualityGateDefaultRules } from "./rules.js";
|
|
10
9
|
export const stringifyQualityGateResults = (results) => {
|
|
@@ -77,6 +76,7 @@ export class QualityGate {
|
|
|
77
76
|
},
|
|
78
77
|
expected,
|
|
79
78
|
knownIssues,
|
|
79
|
+
environment,
|
|
80
80
|
});
|
|
81
81
|
if (result.success) {
|
|
82
82
|
continue;
|
|
@@ -89,7 +89,7 @@ export class QualityGate {
|
|
|
89
89
|
actual: result.actual,
|
|
90
90
|
expected,
|
|
91
91
|
}),
|
|
92
|
-
environment
|
|
92
|
+
environment,
|
|
93
93
|
});
|
|
94
94
|
if (ruleset.fastFail) {
|
|
95
95
|
fastFailed = true;
|
|
@@ -3,4 +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
|
export declare const maxDurationRule: QualityGateRule<number>;
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const allTestsContainEnvRule: QualityGateRule<string>;
|
|
7
|
+
export declare const environmentsTestedRule: QualityGateRule<string[]>;
|
|
8
|
+
export declare const qualityGateDefaultRules: (QualityGateRule<number> | QualityGateRule<string> | QualityGateRule<string[]>)[];
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { filterSuccessful, filterUnsuccessful } from "@allurereport/core-api";
|
|
1
|
+
import { filterSuccessful, filterUnknownByKnownIssues, filterUnsuccessful } from "@allurereport/core-api";
|
|
2
2
|
import { bold } from "yoctocolors";
|
|
3
3
|
export const maxFailuresRule = {
|
|
4
4
|
rule: "maxFailures",
|
|
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, knownIssues, expected, state }) => {
|
|
7
|
-
const knownIssuesHistoryIds = knownIssues.map(({ historyId }) => historyId);
|
|
8
|
-
const unknown = trs
|
|
7
|
+
const knownIssuesHistoryIds = new Set(knownIssues.map(({ historyId }) => historyId));
|
|
8
|
+
const unknown = filterUnknownByKnownIssues(trs, knownIssuesHistoryIds);
|
|
9
9
|
const failedTrs = unknown.filter(filterUnsuccessful);
|
|
10
10
|
const actual = failedTrs.length + (state.getResult() ?? 0);
|
|
11
11
|
state.setResult(actual);
|
|
@@ -31,8 +31,8 @@ export const successRateRule = {
|
|
|
31
31
|
rule: "successRate",
|
|
32
32
|
message: ({ actual, expected }) => `Success rate ${bold(String(actual))} is less, than expected ${bold(String(expected))}`,
|
|
33
33
|
validate: async ({ trs, knownIssues, expected }) => {
|
|
34
|
-
const knownIssuesHistoryIds = knownIssues.map(({ historyId }) => historyId);
|
|
35
|
-
const unknown = trs
|
|
34
|
+
const knownIssuesHistoryIds = new Set(knownIssues.map(({ historyId }) => historyId));
|
|
35
|
+
const unknown = filterUnknownByKnownIssues(trs, knownIssuesHistoryIds);
|
|
36
36
|
const passedTrs = unknown.filter(filterSuccessful);
|
|
37
37
|
const rate = passedTrs.length === 0 ? 0 : passedTrs.length / unknown.length;
|
|
38
38
|
return {
|
|
@@ -52,4 +52,38 @@ export const maxDurationRule = {
|
|
|
52
52
|
};
|
|
53
53
|
},
|
|
54
54
|
};
|
|
55
|
-
export const
|
|
55
|
+
export const allTestsContainEnvRule = {
|
|
56
|
+
rule: "allTestsContainEnv",
|
|
57
|
+
message: ({ actual, expected }) => `Not all tests contain the required environment, ${bold(`"${expected}"`)}; ${bold(actual.length === 1 ? "one" : String(actual))} ${actual.length === 1 ? "test has" : "tests have"} different or missing environment`,
|
|
58
|
+
validate: async ({ trs, expected }) => {
|
|
59
|
+
const testsWithoutEnv = trs.filter((tr) => (tr.environment ?? "") !== expected);
|
|
60
|
+
const actual = testsWithoutEnv.length;
|
|
61
|
+
return {
|
|
62
|
+
success: actual === 0,
|
|
63
|
+
actual,
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
export const environmentsTestedRule = {
|
|
68
|
+
rule: "environmentsTested",
|
|
69
|
+
message: ({ actual, expected }) => `The following environments were not tested: "${actual.join('", "')}"; expected all of: "${expected.join('", "')}"`,
|
|
70
|
+
validate: async ({ trs, expected, state }) => {
|
|
71
|
+
const previouslyTested = new Set(state.getResult() ?? []);
|
|
72
|
+
const batchTested = trs.map((tr) => tr.environment).filter((env) => env != null && env !== "");
|
|
73
|
+
const testedEnvs = new Set([...previouslyTested, ...batchTested]);
|
|
74
|
+
state.setResult([...testedEnvs]);
|
|
75
|
+
const missing = expected.filter((env) => !testedEnvs.has(env));
|
|
76
|
+
return {
|
|
77
|
+
success: missing.length === 0,
|
|
78
|
+
actual: missing,
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
export const qualityGateDefaultRules = [
|
|
83
|
+
maxFailuresRule,
|
|
84
|
+
minTestsCountRule,
|
|
85
|
+
successRateRule,
|
|
86
|
+
maxDurationRule,
|
|
87
|
+
allTestsContainEnvRule,
|
|
88
|
+
environmentsTestedRule,
|
|
89
|
+
];
|
package/dist/report.d.ts
CHANGED