@allurereport/core-api 3.3.1 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/categories.d.ts +2 -0
- package/dist/categories.js +42 -2
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/environment.d.ts +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/static.d.ts +1 -0
- package/dist/static.js +11 -1
- package/dist/utils/environment.d.ts +16 -3
- package/dist/utils/environment.js +73 -3
- package/dist/utils/history.d.ts +7 -0
- package/dist/utils/history.js +82 -15
- package/dist/utils/label.d.ts +1 -0
- package/dist/utils/label.js +11 -0
- package/dist/utils/path.d.ts +2 -0
- package/dist/utils/path.js +11 -0
- package/dist/utils/url.d.ts +1 -0
- package/dist/utils/url.js +24 -0
- package/package.json +11 -22
package/dist/categories.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export type CategoryGroupCustomSelector = {
|
|
|
38
38
|
};
|
|
39
39
|
export type CategoryGroupSelector = CategoryGroupBuiltInSelector | CategoryGroupCustomSelector;
|
|
40
40
|
export type CategoryRule = {
|
|
41
|
+
id?: string;
|
|
41
42
|
name: string;
|
|
42
43
|
matchers?: CategoryMatcher;
|
|
43
44
|
groupBy?: readonly CategoryGroupSelector[];
|
|
@@ -55,6 +56,7 @@ export type CategoriesStore = {
|
|
|
55
56
|
nodes: Record<string, CategoryNode>;
|
|
56
57
|
};
|
|
57
58
|
export interface CategoryDefinition extends Pick<CategoryRule, "name" | "expand" | "hide" | "groupEnvironments"> {
|
|
59
|
+
id: string;
|
|
58
60
|
matchers: Matcher[];
|
|
59
61
|
groupBy: CategoryGroupSelector[];
|
|
60
62
|
groupByMessage: boolean;
|
package/dist/categories.js
CHANGED
|
@@ -32,6 +32,28 @@ export const DEFAULT_ERROR_CATEGORIES = [
|
|
|
32
32
|
const isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
33
33
|
const toRegExp = (v) => (v instanceof RegExp ? v : new RegExp(v));
|
|
34
34
|
const isMatcherArray = (value) => Array.isArray(value);
|
|
35
|
+
const hasControlChars = (value) => {
|
|
36
|
+
for (let index = 0; index < value.length; index++) {
|
|
37
|
+
const code = value.charCodeAt(index);
|
|
38
|
+
if (code <= 0x1f || (code >= 0x7f && code <= 0x9f)) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
};
|
|
44
|
+
const normalizeCategoryId = (id) => {
|
|
45
|
+
if (typeof id !== "string") {
|
|
46
|
+
return { valid: false, reason: "id must be a string" };
|
|
47
|
+
}
|
|
48
|
+
const normalized = id.trim();
|
|
49
|
+
if (normalized.length === 0) {
|
|
50
|
+
return { valid: false, reason: "id must not be empty" };
|
|
51
|
+
}
|
|
52
|
+
if (hasControlChars(normalized)) {
|
|
53
|
+
return { valid: false, reason: "id must not contain control characters" };
|
|
54
|
+
}
|
|
55
|
+
return { valid: true, normalized };
|
|
56
|
+
};
|
|
35
57
|
const normalizeMatchers = (rule, index) => {
|
|
36
58
|
const compatKeysUsed = rule.matchedStatuses !== undefined ||
|
|
37
59
|
rule.messageRegex !== undefined ||
|
|
@@ -85,6 +107,7 @@ export const normalizeCategoriesConfig = (cfg) => {
|
|
|
85
107
|
const rules = rawRules.length ? rawRules : [];
|
|
86
108
|
const normalized = [];
|
|
87
109
|
const seen = new Map();
|
|
110
|
+
const sourceIdsByNormalizedId = new Map();
|
|
88
111
|
const applyRule = (rule, index) => {
|
|
89
112
|
if (!isPlainObject(rule)) {
|
|
90
113
|
throw new Error(`categories[${index}] must be an object`);
|
|
@@ -92,8 +115,16 @@ export const normalizeCategoriesConfig = (cfg) => {
|
|
|
92
115
|
if (typeof rule.name !== "string" || !rule.name.trim()) {
|
|
93
116
|
throw new Error(`categories[${index}].name must be non-empty string`);
|
|
94
117
|
}
|
|
118
|
+
const idValidationResult = normalizeCategoryId(rule.id ?? rule.name);
|
|
119
|
+
if (!idValidationResult.valid) {
|
|
120
|
+
throw new Error(`categories[${index}].id ${idValidationResult.reason}`);
|
|
121
|
+
}
|
|
122
|
+
const normalizedId = idValidationResult.normalized;
|
|
123
|
+
const sourceIds = sourceIdsByNormalizedId.get(normalizedId) ?? new Set();
|
|
124
|
+
sourceIds.add(rule.id ?? rule.name);
|
|
125
|
+
sourceIdsByNormalizedId.set(normalizedId, sourceIds);
|
|
95
126
|
const matchers = normalizeMatchers(rule, index);
|
|
96
|
-
const existing = seen.get(
|
|
127
|
+
const existing = seen.get(normalizedId);
|
|
97
128
|
if (existing) {
|
|
98
129
|
existing.matchers.push(...matchers);
|
|
99
130
|
return;
|
|
@@ -118,6 +149,7 @@ export const normalizeCategoriesConfig = (cfg) => {
|
|
|
118
149
|
}
|
|
119
150
|
}
|
|
120
151
|
const norm = {
|
|
152
|
+
id: normalizedId,
|
|
121
153
|
name: rule.name,
|
|
122
154
|
matchers,
|
|
123
155
|
groupBy,
|
|
@@ -127,11 +159,19 @@ export const normalizeCategoriesConfig = (cfg) => {
|
|
|
127
159
|
hide: rule.hide ?? false,
|
|
128
160
|
index,
|
|
129
161
|
};
|
|
130
|
-
seen.set(
|
|
162
|
+
seen.set(normalizedId, norm);
|
|
131
163
|
normalized.push(norm);
|
|
132
164
|
};
|
|
133
165
|
rules.forEach(applyRule);
|
|
134
166
|
DEFAULT_ERROR_CATEGORIES.forEach((rule, index) => applyRule(rule, rules.length + index));
|
|
167
|
+
sourceIdsByNormalizedId.forEach((sourceIds, normalizedId) => {
|
|
168
|
+
if (sourceIds.size <= 1) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
throw new Error(`categories: normalized id ${JSON.stringify(normalizedId)} is produced by source ids [${Array.from(sourceIds)
|
|
172
|
+
.map((id) => JSON.stringify(id))
|
|
173
|
+
.join(",")}]`);
|
|
174
|
+
});
|
|
135
175
|
return normalized;
|
|
136
176
|
};
|
|
137
177
|
const matchObjectMatcher = (m, d) => {
|
package/dist/constants.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { SeverityLevel, TestStatus } from "./model.js";
|
|
|
3
3
|
export declare const statusesList: readonly TestStatus[];
|
|
4
4
|
export declare const severityLevels: readonly SeverityLevel[];
|
|
5
5
|
export declare const severityLabelName = "severity";
|
|
6
|
+
export declare const fallbackTestCaseIdLabelName = "_fallbackTestCaseId";
|
|
6
7
|
export declare const unsuccessfulStatuses: Set<TestStatus>;
|
|
7
8
|
export declare const successfulStatuses: Set<TestStatus>;
|
|
8
9
|
export declare const includedInSuccessRate: Set<TestStatus>;
|
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export const statusesList = ["failed", "broken", "passed", "skipped", "unknown"];
|
|
2
2
|
export const severityLevels = ["blocker", "critical", "normal", "minor", "trivial"];
|
|
3
3
|
export const severityLabelName = "severity";
|
|
4
|
+
export const fallbackTestCaseIdLabelName = "_fallbackTestCaseId";
|
|
4
5
|
export const unsuccessfulStatuses = new Set(["failed", "broken"]);
|
|
5
6
|
export const successfulStatuses = new Set(["passed"]);
|
|
6
7
|
export const includedInSuccessRate = new Set([...unsuccessfulStatuses, ...successfulStatuses]);
|
package/dist/environment.d.ts
CHANGED
|
@@ -3,11 +3,16 @@ export interface EnvironmentItem {
|
|
|
3
3
|
name: string;
|
|
4
4
|
values: string[];
|
|
5
5
|
}
|
|
6
|
+
export interface EnvironmentIdentity {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
6
10
|
export type ReportVariables = Record<string, string>;
|
|
7
11
|
export type EnvironmentMatcherPayload = {
|
|
8
12
|
labels: TestLabel[];
|
|
9
13
|
};
|
|
10
14
|
export type EnvironmentDescriptor = {
|
|
15
|
+
name?: string;
|
|
11
16
|
variables?: ReportVariables;
|
|
12
17
|
matcher: (payload: EnvironmentMatcherPayload) => boolean;
|
|
13
18
|
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/static.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare const createStylesLinkTag: (src: string) => string;
|
|
|
6
6
|
export declare const createFontLinkTag: (src: string) => string;
|
|
7
7
|
export declare const createFaviconLinkTag: (src: string) => string;
|
|
8
8
|
export declare const createBaseUrlScript: () => string;
|
|
9
|
+
export declare const stringifyForInlineScript: (value: unknown) => string;
|
|
9
10
|
export declare const createReportDataScript: (reportFiles?: {
|
|
10
11
|
name: string;
|
|
11
12
|
value: string;
|
package/dist/static.js
CHANGED
|
@@ -23,6 +23,14 @@ export const createBaseUrlScript = () => {
|
|
|
23
23
|
</script>
|
|
24
24
|
`;
|
|
25
25
|
};
|
|
26
|
+
export const stringifyForInlineScript = (value) => {
|
|
27
|
+
return JSON.stringify(value)
|
|
28
|
+
.replaceAll("<", "\\u003C")
|
|
29
|
+
.replaceAll(">", "\\u003E")
|
|
30
|
+
.replaceAll("&", "\\u0026")
|
|
31
|
+
.replaceAll("\u2028", "\\u2028")
|
|
32
|
+
.replaceAll("\u2029", "\\u2029");
|
|
33
|
+
};
|
|
26
34
|
export const createReportDataScript = (reportFiles = []) => {
|
|
27
35
|
if (!reportFiles?.length) {
|
|
28
36
|
return `
|
|
@@ -31,7 +39,9 @@ export const createReportDataScript = (reportFiles = []) => {
|
|
|
31
39
|
</script>
|
|
32
40
|
`;
|
|
33
41
|
}
|
|
34
|
-
const reportFilesDeclaration = reportFiles
|
|
42
|
+
const reportFilesDeclaration = reportFiles
|
|
43
|
+
.map(({ name, value }) => `d(${JSON.stringify(name)},${JSON.stringify(value)})`)
|
|
44
|
+
.join(",");
|
|
35
45
|
return `
|
|
36
46
|
<script async>
|
|
37
47
|
window.allureReportDataReady = false;
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { TestEnvGroup
|
|
1
|
+
import type { EnvironmentIdentity } from "../environment.js";
|
|
2
|
+
import type { TestEnvGroup } from "../model.js";
|
|
3
3
|
export declare const DEFAULT_ENVIRONMENT = "default";
|
|
4
|
-
export declare const
|
|
4
|
+
export declare const MAX_ENVIRONMENT_NAME_LENGTH = 64;
|
|
5
|
+
export declare const MAX_ENVIRONMENT_ID_LENGTH = 64;
|
|
6
|
+
export declare const DEFAULT_ENVIRONMENT_IDENTITY: EnvironmentIdentity;
|
|
7
|
+
export type EnvironmentValidationResult = {
|
|
8
|
+
valid: true;
|
|
9
|
+
normalized: string;
|
|
10
|
+
} | {
|
|
11
|
+
valid: false;
|
|
12
|
+
reason: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const validateEnvironmentName: (name: unknown) => EnvironmentValidationResult;
|
|
15
|
+
export declare const validateEnvironmentId: (environmentId: unknown) => EnvironmentValidationResult;
|
|
16
|
+
export declare const assertValidEnvironmentName: (name: unknown, source?: string) => string;
|
|
17
|
+
export declare const formatNormalizedEnvironmentCollision: (sourcePath: string, normalized: string, originalKeys: string[]) => string;
|
|
5
18
|
export declare const getRealEnvsCount: (group: TestEnvGroup) => number;
|
|
@@ -1,10 +1,80 @@
|
|
|
1
1
|
export const DEFAULT_ENVIRONMENT = "default";
|
|
2
|
-
export const
|
|
3
|
-
|
|
2
|
+
export const MAX_ENVIRONMENT_NAME_LENGTH = 64;
|
|
3
|
+
export const MAX_ENVIRONMENT_ID_LENGTH = 64;
|
|
4
|
+
export const DEFAULT_ENVIRONMENT_IDENTITY = {
|
|
5
|
+
id: DEFAULT_ENVIRONMENT,
|
|
6
|
+
name: DEFAULT_ENVIRONMENT,
|
|
4
7
|
};
|
|
8
|
+
const hasControlChars = (value) => {
|
|
9
|
+
for (let i = 0; i < value.length; i++) {
|
|
10
|
+
const code = value.charCodeAt(i);
|
|
11
|
+
if (code <= 0x1f || (code >= 0x7f && code <= 0x9f)) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
};
|
|
17
|
+
const hasPathLikeSegments = (value) => {
|
|
18
|
+
if (value.includes("/") || value.includes("\\")) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
return value === "." || value === "..";
|
|
22
|
+
};
|
|
23
|
+
export const validateEnvironmentName = (name) => {
|
|
24
|
+
if (typeof name !== "string") {
|
|
25
|
+
return { valid: false, reason: "name must be a string" };
|
|
26
|
+
}
|
|
27
|
+
const normalized = name.trim();
|
|
28
|
+
if (normalized.length === 0) {
|
|
29
|
+
return { valid: false, reason: "name must not be empty" };
|
|
30
|
+
}
|
|
31
|
+
if (normalized.length > MAX_ENVIRONMENT_NAME_LENGTH) {
|
|
32
|
+
return {
|
|
33
|
+
valid: false,
|
|
34
|
+
reason: `name must not exceed ${MAX_ENVIRONMENT_NAME_LENGTH} characters`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (hasControlChars(normalized)) {
|
|
38
|
+
return { valid: false, reason: "name must not contain control characters" };
|
|
39
|
+
}
|
|
40
|
+
if (hasPathLikeSegments(normalized)) {
|
|
41
|
+
return { valid: false, reason: "name must not contain path-like segments" };
|
|
42
|
+
}
|
|
43
|
+
return { valid: true, normalized };
|
|
44
|
+
};
|
|
45
|
+
export const validateEnvironmentId = (environmentId) => {
|
|
46
|
+
if (typeof environmentId !== "string") {
|
|
47
|
+
return { valid: false, reason: "id must be a string" };
|
|
48
|
+
}
|
|
49
|
+
const normalized = environmentId.trim();
|
|
50
|
+
if (normalized.length === 0) {
|
|
51
|
+
return { valid: false, reason: "id must not be empty" };
|
|
52
|
+
}
|
|
53
|
+
if (normalized.length > MAX_ENVIRONMENT_ID_LENGTH) {
|
|
54
|
+
return {
|
|
55
|
+
valid: false,
|
|
56
|
+
reason: `id must not exceed ${MAX_ENVIRONMENT_ID_LENGTH} characters`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (!/^[A-Za-z0-9_-]+$/.test(normalized)) {
|
|
60
|
+
return {
|
|
61
|
+
valid: false,
|
|
62
|
+
reason: "id must contain only latin letters, digits, underscores, and hyphens",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return { valid: true, normalized };
|
|
66
|
+
};
|
|
67
|
+
export const assertValidEnvironmentName = (name, source = "environment name") => {
|
|
68
|
+
const validationResult = validateEnvironmentName(name);
|
|
69
|
+
if (!validationResult.valid) {
|
|
70
|
+
throw new Error(`Invalid ${source} ${JSON.stringify(name)}: ${validationResult.reason}`);
|
|
71
|
+
}
|
|
72
|
+
return validationResult.normalized;
|
|
73
|
+
};
|
|
74
|
+
export const formatNormalizedEnvironmentCollision = (sourcePath, normalized, originalKeys) => `${sourcePath}: normalized key ${JSON.stringify(normalized)} is produced by original keys [${originalKeys.map((key) => JSON.stringify(key)).join(",")}]`;
|
|
5
75
|
export const getRealEnvsCount = (group) => {
|
|
6
76
|
const { testResultsByEnv = {} } = group ?? {};
|
|
7
|
-
const envsCount = Object.keys(testResultsByEnv).length
|
|
77
|
+
const envsCount = Object.keys(testResultsByEnv).length;
|
|
8
78
|
if (envsCount <= 1 && DEFAULT_ENVIRONMENT in testResultsByEnv) {
|
|
9
79
|
return 0;
|
|
10
80
|
}
|
package/dist/utils/history.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import type { HistoryDataPoint, HistoryTestResult } from "../history.js";
|
|
2
|
+
import type { TestParameter } from "../metadata.js";
|
|
2
3
|
import type { TestResult } from "../model.js";
|
|
4
|
+
export declare const stringifyHistoryParams: (parameters?: TestParameter[]) => string;
|
|
5
|
+
export declare const getFallbackHistoryId: (tr: Pick<TestResult, "labels" | "parameters">) => string | undefined;
|
|
6
|
+
export declare const getHistoryIdCandidates: (tr: Pick<TestResult, "historyId" | "labels" | "parameters">) => string[];
|
|
7
|
+
export declare const filterUnknownByKnownIssues: (trs: TestResult[], knownIssueHistoryIds: ReadonlySet<string>) => TestResult[];
|
|
8
|
+
export declare const normalizeHistoryDataPointUrls: (historyDataPoint: HistoryDataPoint) => HistoryDataPoint;
|
|
9
|
+
export declare const selectHistoryTestResults: (historyDataPoints: HistoryDataPoint[], historyIdCandidates: readonly string[]) => HistoryTestResult[];
|
|
3
10
|
export declare const htrsByTr: (hdps: HistoryDataPoint[], tr: TestResult | HistoryTestResult) => HistoryTestResult[];
|
package/dist/utils/history.js
CHANGED
|
@@ -1,22 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { fallbackTestCaseIdLabelName } from "../constants.js";
|
|
3
|
+
import { findLastByLabelName } from "./label.js";
|
|
4
|
+
const md5 = (data) => createHash("md5").update(data).digest("hex");
|
|
5
|
+
const parametersCompare = (a, b) => {
|
|
6
|
+
return (a.name ?? "").localeCompare(b.name ?? "") || (a.value ?? "").localeCompare(b.value ?? "");
|
|
7
|
+
};
|
|
8
|
+
export const stringifyHistoryParams = (parameters = []) => {
|
|
9
|
+
return [...parameters]
|
|
10
|
+
.filter((parameter) => !parameter?.excluded)
|
|
11
|
+
.sort(parametersCompare)
|
|
12
|
+
.map((parameter) => `${parameter.name}:${parameter.value}`)
|
|
13
|
+
.join(",");
|
|
14
|
+
};
|
|
15
|
+
export const getFallbackHistoryId = (tr) => {
|
|
16
|
+
const fallbackTestCaseId = findLastByLabelName(tr.labels ?? [], fallbackTestCaseIdLabelName);
|
|
17
|
+
if (!fallbackTestCaseId) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
return `${fallbackTestCaseId}.${md5(stringifyHistoryParams(tr.parameters ?? []))}`;
|
|
21
|
+
};
|
|
22
|
+
export const getHistoryIdCandidates = (tr) => {
|
|
23
|
+
const result = [];
|
|
24
|
+
if (tr.historyId) {
|
|
25
|
+
result.push(tr.historyId);
|
|
26
|
+
}
|
|
27
|
+
const fallbackHistoryId = getFallbackHistoryId(tr);
|
|
28
|
+
if (fallbackHistoryId && !result.includes(fallbackHistoryId)) {
|
|
29
|
+
result.push(fallbackHistoryId);
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
};
|
|
33
|
+
export const filterUnknownByKnownIssues = (trs, knownIssueHistoryIds) => {
|
|
34
|
+
return trs.filter((tr) => {
|
|
35
|
+
const historyIdCandidates = getHistoryIdCandidates(tr);
|
|
36
|
+
if (historyIdCandidates.length === 0) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return historyIdCandidates.every((historyId) => !knownIssueHistoryIds.has(historyId));
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
export const normalizeHistoryDataPointUrls = (historyDataPoint) => {
|
|
43
|
+
const { url } = historyDataPoint;
|
|
44
|
+
if (!url) {
|
|
45
|
+
return historyDataPoint;
|
|
46
|
+
}
|
|
47
|
+
let testResults = historyDataPoint.testResults;
|
|
48
|
+
for (const [historyId, historyTestResult] of Object.entries(historyDataPoint.testResults)) {
|
|
49
|
+
if (historyTestResult.url) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (testResults === historyDataPoint.testResults) {
|
|
53
|
+
testResults = { ...historyDataPoint.testResults };
|
|
54
|
+
}
|
|
55
|
+
testResults[historyId] = {
|
|
56
|
+
...historyTestResult,
|
|
57
|
+
url,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (testResults === historyDataPoint.testResults) {
|
|
61
|
+
return historyDataPoint;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
...historyDataPoint,
|
|
65
|
+
testResults,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export const selectHistoryTestResults = (historyDataPoints, historyIdCandidates) => {
|
|
69
|
+
if (historyIdCandidates.length === 0) {
|
|
3
70
|
return [];
|
|
4
71
|
}
|
|
5
|
-
return
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
if (
|
|
9
|
-
|
|
10
|
-
url.hash = tr.id;
|
|
11
|
-
acc.push({
|
|
12
|
-
...htr,
|
|
13
|
-
url: url.toString(),
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
acc.push(htr);
|
|
72
|
+
return historyDataPoints.reduce((acc, historyDataPoint) => {
|
|
73
|
+
for (const historyId of historyIdCandidates) {
|
|
74
|
+
const historyTestResult = historyDataPoint.testResults[historyId];
|
|
75
|
+
if (!historyTestResult) {
|
|
76
|
+
continue;
|
|
18
77
|
}
|
|
78
|
+
acc.push(historyTestResult);
|
|
79
|
+
break;
|
|
19
80
|
}
|
|
20
81
|
return acc;
|
|
21
82
|
}, []);
|
|
22
83
|
};
|
|
84
|
+
export const htrsByTr = (hdps, tr) => {
|
|
85
|
+
if (!tr?.historyId) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
return selectHistoryTestResults(hdps, [tr.historyId]);
|
|
89
|
+
};
|
package/dist/utils/label.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { TestLabel } from "../index.js";
|
|
2
2
|
export declare const findByLabelName: (labels: TestLabel[], name: string) => string | undefined;
|
|
3
3
|
export declare const findLastByLabelName: (labels: TestLabel[], name: string) => string | undefined;
|
|
4
|
+
export declare const shouldHideLabel: (labelName: string, matchers?: readonly (string | RegExp)[]) => boolean;
|
package/dist/utils/label.js
CHANGED
|
@@ -9,3 +9,14 @@ export const findLastByLabelName = (labels, name) => {
|
|
|
9
9
|
}
|
|
10
10
|
return undefined;
|
|
11
11
|
};
|
|
12
|
+
export const shouldHideLabel = (labelName, matchers = []) => {
|
|
13
|
+
if (labelName.startsWith("_")) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
return matchers.some((matcher) => {
|
|
17
|
+
if (typeof matcher === "string") {
|
|
18
|
+
return matcher === labelName;
|
|
19
|
+
}
|
|
20
|
+
return new RegExp(matcher.source, matcher.flags).test(labelName);
|
|
21
|
+
});
|
|
22
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const toPosixPath = (path) => path.replace(/\\/g, "/");
|
|
2
|
+
export const joinPosixPath = (...parts) => {
|
|
3
|
+
const segments = parts.map(toPosixPath).join("/").split("/");
|
|
4
|
+
const nonEmptySegments = [];
|
|
5
|
+
for (const segment of segments) {
|
|
6
|
+
if (segment.length > 0) {
|
|
7
|
+
nonEmptySegments.push(segment);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return nonEmptySegments.join("/");
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sanitizeExternalUrl: (value: unknown) => string | undefined;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const ALLOWED_EXTERNAL_URL_PROTOCOLS = new Set(["http:", "https:", "mailto:", "tel:"]);
|
|
2
|
+
export const sanitizeExternalUrl = (value) => {
|
|
3
|
+
if (typeof value !== "string") {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
const normalized = value.trim();
|
|
7
|
+
if (normalized.length === 0) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const schemeMatch = normalized.match(/^([A-Za-z][A-Za-z0-9+.-]*):/);
|
|
11
|
+
if (!schemeMatch) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const protocol = `${schemeMatch[1].toLowerCase()}:`;
|
|
15
|
+
if (!ALLOWED_EXTERNAL_URL_PROTOCOLS.has(protocol)) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
return new URL(normalized).toString();
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
};
|
package/package.json
CHANGED
|
@@ -1,50 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allurereport/core-api",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.1",
|
|
4
4
|
"description": "Allure Core API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"allure"
|
|
7
7
|
],
|
|
8
|
-
"repository": "https://github.com/allure-framework/allure3",
|
|
9
8
|
"license": "Apache-2.0",
|
|
10
9
|
"author": "Qameta Software",
|
|
10
|
+
"repository": "https://github.com/allure-framework/allure3",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
11
14
|
"type": "module",
|
|
12
|
-
"exports": {
|
|
13
|
-
".": "./dist/index.js"
|
|
14
|
-
},
|
|
15
15
|
"main": "./dist/index.js",
|
|
16
16
|
"module": "./dist/index.js",
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
|
-
"
|
|
19
|
-
"dist"
|
|
20
|
-
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./dist/index.js"
|
|
20
|
+
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "run clean && tsc --project ./tsconfig.json",
|
|
23
23
|
"clean": "rimraf ./dist",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
24
|
+
"test": "rimraf ./out && vitest run",
|
|
25
|
+
"lint": "oxlint --import-plugin src test features stories",
|
|
26
|
+
"lint:fix": "oxlint --import-plugin --fix src test features stories"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"d3-shape": "^3.2.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@stylistic/eslint-plugin": "^2.6.1",
|
|
33
32
|
"@types/d3-shape": "^3.1.6",
|
|
34
|
-
"@types/eslint": "^8.56.11",
|
|
35
33
|
"@types/node": "^20.17.9",
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
37
|
-
"@typescript-eslint/parser": "^8.0.0",
|
|
38
34
|
"@vitest/runner": "^2.1.9",
|
|
39
35
|
"@vitest/snapshot": "^2.1.9",
|
|
40
36
|
"allure-vitest": "^3.3.3",
|
|
41
|
-
"eslint": "^8.57.0",
|
|
42
|
-
"eslint-config-prettier": "^9.1.0",
|
|
43
|
-
"eslint-plugin-import": "^2.29.1",
|
|
44
|
-
"eslint-plugin-jsdoc": "^50.0.0",
|
|
45
|
-
"eslint-plugin-n": "^17.10.1",
|
|
46
|
-
"eslint-plugin-no-null": "^1.0.2",
|
|
47
|
-
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
48
37
|
"rimraf": "^6.0.1",
|
|
49
38
|
"typescript": "^5.6.3",
|
|
50
39
|
"vitest": "^2.1.9"
|