@allurereport/web-commons 3.21.0 → 3.22.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/attachments.js +4 -3
- package/dist/charts/config.d.ts +2 -0
- package/dist/charts/config.js +15 -0
- package/dist/charts/generateStabilityDistributionChart.d.ts +0 -2
- package/dist/charts/generateStabilityDistributionChart.js +37 -132
- package/dist/charts/index.d.ts +1 -0
- package/dist/charts/index.js +1 -0
- package/dist/contentTypes.d.ts +5 -0
- package/dist/contentTypes.js +11 -0
- package/dist/httpAttachments.d.ts +79 -0
- package/dist/httpAttachments.js +160 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/platform.d.ts +1 -0
- package/dist/platform.js +8 -0
- package/dist/stores/url/store.d.ts +0 -3
- package/dist/stores/url/store.js +0 -3
- package/package.json +13 -11
package/dist/attachments.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { normalizeAttachmentContentType } from "./contentTypes.js";
|
|
1
2
|
import { fetchReportAttachment } from "./data.js";
|
|
2
3
|
const PLAYWRIGHT_TRACE_CONTENT_TYPE = "application/vnd.allure.playwright-trace";
|
|
3
4
|
const PLAYWRIGHT_TRACE_DOWNLOAD_CONTENT_TYPE = "application/zip";
|
|
4
5
|
const downloadContentType = (contentType) => {
|
|
5
|
-
return contentType
|
|
6
|
+
return normalizeAttachmentContentType(contentType) === PLAYWRIGHT_TRACE_CONTENT_TYPE
|
|
6
7
|
? PLAYWRIGHT_TRACE_DOWNLOAD_CONTENT_TYPE
|
|
7
8
|
: contentType;
|
|
8
9
|
};
|
|
@@ -87,7 +88,7 @@ export const PREVIEWABLE_CONTENT_TYPES = [
|
|
|
87
88
|
"text/tab-separated-values",
|
|
88
89
|
"text/uri-list",
|
|
89
90
|
];
|
|
90
|
-
export const isPreviewableContentType = (type) => !!type && PREVIEWABLE_CONTENT_TYPES.includes(type
|
|
91
|
+
export const isPreviewableContentType = (type) => !!type && PREVIEWABLE_CONTENT_TYPES.includes(normalizeAttachmentContentType(type));
|
|
91
92
|
const HIGHLIGHT_EXTS = new Set([
|
|
92
93
|
"js",
|
|
93
94
|
"mjs",
|
|
@@ -196,7 +197,7 @@ export const isSyntaxHighlightSupported = (payload) => {
|
|
|
196
197
|
return !!ext && HIGHLIGHT_EXTS.has(ext);
|
|
197
198
|
};
|
|
198
199
|
export const attachmentType = (type) => {
|
|
199
|
-
const normalizedType = type
|
|
200
|
+
const normalizedType = normalizeAttachmentContentType(type);
|
|
200
201
|
switch (normalizedType) {
|
|
201
202
|
case "image/bmp":
|
|
202
203
|
case "image/gif":
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ChartType } from "@allurereport/charts-api";
|
|
2
|
+
export const validateChartsOptions = (charts) => {
|
|
3
|
+
for (const options of charts) {
|
|
4
|
+
if (options.type !== ChartType.StabilityDistribution) {
|
|
5
|
+
continue;
|
|
6
|
+
}
|
|
7
|
+
const { limit, stabilizationPeriod } = options;
|
|
8
|
+
if (limit !== undefined && (!Number.isInteger(limit) || limit < 0)) {
|
|
9
|
+
throw new RangeError("stabilityDistribution.limit must be a non-negative integer");
|
|
10
|
+
}
|
|
11
|
+
if (stabilizationPeriod !== undefined && (!Number.isInteger(stabilizationPeriod) || stabilizationPeriod < 1)) {
|
|
12
|
+
throw new RangeError("stabilityDistribution.stabilizationPeriod must be a positive integer");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { AllureChartsStoreData, StabilityDistributionChartData, StabilityDistributionChartOptions } from "@allurereport/charts-api";
|
|
2
|
-
import { type TestStatus } from "@allurereport/core-api";
|
|
3
|
-
export declare const getStabilityScore: (statuses: TestStatus[], historyDepth: number, stabilizationPeriod: number) => number | undefined;
|
|
4
2
|
export declare const generateStabilityDistributionChart: (props: {
|
|
5
3
|
options: StabilityDistributionChartOptions;
|
|
6
4
|
storeData: AllureChartsStoreData;
|
|
@@ -1,158 +1,63 @@
|
|
|
1
1
|
import { ChartType } from "@allurereport/charts-api";
|
|
2
|
-
import { createHistoryTestResultLookup, } from "@allurereport/core-api";
|
|
3
|
-
import { createHashStorage
|
|
4
|
-
const DEFAULT_LIMIT = 10;
|
|
5
|
-
const DEFAULT_STABILIZATION_PERIOD = 5;
|
|
2
|
+
import { createHistoryTestResultLookup, getTestFlakiness } from "@allurereport/core-api";
|
|
3
|
+
import { createHashStorage } from "./utils.js";
|
|
6
4
|
const DEFAULT_THRESHOLD = 90;
|
|
7
5
|
const DEFAULT_GROUP_BY = "feature";
|
|
8
6
|
const CUSTOM_LABEL_NAME_PREFIX = "label-name:";
|
|
9
7
|
const SIGNIFICANT_STATUSES = new Set(["passed", "failed", "broken"]);
|
|
10
|
-
const isSignificantStatus = (status) => SIGNIFICANT_STATUSES.has(status);
|
|
11
|
-
const getTrLabelValue = (testResult, labelName) => {
|
|
12
|
-
return testResult.labels?.find((label) => label.name === labelName)?.value;
|
|
13
|
-
};
|
|
14
8
|
const NON_SIGNIFICANT_STATUSES = ["unknown", "skipped"];
|
|
15
|
-
const findLatestConsecutiveSameBlock = (statuses, sequenceLength, blockSize) => {
|
|
16
|
-
for (let start = sequenceLength - blockSize; start >= 0; start--) {
|
|
17
|
-
const first = statuses[start];
|
|
18
|
-
let allSame = true;
|
|
19
|
-
for (let k = 1; k < blockSize; k++) {
|
|
20
|
-
if (statuses[start + k] !== first) {
|
|
21
|
-
allSame = false;
|
|
22
|
-
break;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
if (allSame) {
|
|
26
|
-
return { endIndex: start + blockSize - 1, status: first };
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return null;
|
|
30
|
-
};
|
|
31
|
-
const computeTransitionsInRange = (statuses, firstEdge, lastEdge) => {
|
|
32
|
-
let transitionCount = 0;
|
|
33
|
-
let firstTransitionIdx = 0;
|
|
34
|
-
let secondTransitionIdx = 0;
|
|
35
|
-
let instabilitySumNumerator = 0;
|
|
36
|
-
for (let i = firstEdge; i <= lastEdge; i++) {
|
|
37
|
-
if (statuses[i - 1] === statuses[i]) {
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
transitionCount++;
|
|
41
|
-
if (transitionCount === 1) {
|
|
42
|
-
firstTransitionIdx = i;
|
|
43
|
-
}
|
|
44
|
-
else if (transitionCount === 2) {
|
|
45
|
-
secondTransitionIdx = i;
|
|
46
|
-
}
|
|
47
|
-
instabilitySumNumerator += i;
|
|
48
|
-
}
|
|
49
|
-
return { transitionCount, firstTransitionIdx, secondTransitionIdx, instabilitySumNumerator };
|
|
50
|
-
};
|
|
51
|
-
const isRecoveryTolerancePattern = (statuses, firstTransitionIdx, secondTransitionIdx) => {
|
|
52
|
-
const s0 = statuses[firstTransitionIdx - 1];
|
|
53
|
-
const s1 = statuses[firstTransitionIdx];
|
|
54
|
-
const s2 = statuses[secondTransitionIdx - 1];
|
|
55
|
-
const s3 = statuses[secondTransitionIdx];
|
|
56
|
-
return ((s0 === "passed" && s1 === "broken" && s2 === "broken" && s3 === "passed") ||
|
|
57
|
-
(s0 === "passed" && s1 === "failed" && s2 === "failed" && s3 === "passed"));
|
|
58
|
-
};
|
|
59
|
-
export const getStabilityScore = (statuses, historyDepth, stabilizationPeriod) => {
|
|
60
|
-
const effectiveSequenceLength = Math.min(statuses.length, historyDepth);
|
|
61
|
-
if (effectiveSequenceLength === 0) {
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
64
|
-
if (effectiveSequenceLength === 1) {
|
|
65
|
-
return 1;
|
|
66
|
-
}
|
|
67
|
-
const stabilBlock = findLatestConsecutiveSameBlock(statuses, effectiveSequenceLength, stabilizationPeriod);
|
|
68
|
-
if (stabilBlock !== null && stabilBlock.endIndex === effectiveSequenceLength - 1) {
|
|
69
|
-
return 1;
|
|
70
|
-
}
|
|
71
|
-
const firstEdgeAfterStabilBlock = stabilBlock !== null ? stabilBlock.endIndex + 1 : 1;
|
|
72
|
-
const lastEdge = effectiveSequenceLength - 1;
|
|
73
|
-
const denominator = ((effectiveSequenceLength - 1) * effectiveSequenceLength) / 2;
|
|
74
|
-
const { transitionCount, firstTransitionIdx, secondTransitionIdx, instabilitySumNumerator } = computeTransitionsInRange(statuses, firstEdgeAfterStabilBlock, lastEdge);
|
|
75
|
-
if (transitionCount === 1) {
|
|
76
|
-
return 1;
|
|
77
|
-
}
|
|
78
|
-
if (transitionCount === 2 && isRecoveryTolerancePattern(statuses, firstTransitionIdx, secondTransitionIdx)) {
|
|
79
|
-
return 1;
|
|
80
|
-
}
|
|
81
|
-
return instabilitySumNumerator / denominator;
|
|
82
|
-
};
|
|
83
|
-
const getStatusSequence = (historyDataPoints, tr, lookupHistoryTestResult) => {
|
|
84
|
-
let block = [];
|
|
85
|
-
for (const hdp of historyDataPoints) {
|
|
86
|
-
const htr = lookupHistoryTestResult(hdp, tr);
|
|
87
|
-
if (!htr) {
|
|
88
|
-
block = [];
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (isSignificantStatus(htr.status)) {
|
|
92
|
-
block.push(htr.status);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (isSignificantStatus(tr.status)) {
|
|
96
|
-
block.push(tr.status);
|
|
97
|
-
}
|
|
98
|
-
return block;
|
|
99
|
-
};
|
|
100
9
|
export const generateStabilityDistributionChart = (props) => {
|
|
101
10
|
const { options, storeData } = props;
|
|
102
|
-
const { title, limit
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
threshold,
|
|
113
|
-
};
|
|
11
|
+
const { title, limit, stabilizationPeriod, threshold = DEFAULT_THRESHOLD, skipStatuses: skipStatusesList = NON_SIGNIFICANT_STATUSES, groupBy = DEFAULT_GROUP_BY, groupValues = [], } = options;
|
|
12
|
+
const chart = {
|
|
13
|
+
data: [],
|
|
14
|
+
keys: {},
|
|
15
|
+
type: ChartType.StabilityDistribution,
|
|
16
|
+
title,
|
|
17
|
+
threshold,
|
|
18
|
+
};
|
|
19
|
+
if (limit === 0) {
|
|
20
|
+
return chart;
|
|
114
21
|
}
|
|
115
|
-
const
|
|
22
|
+
const { testResults, historyDataPoints } = storeData;
|
|
23
|
+
const lookup = createHistoryTestResultLookup(storeData.allTestResults ?? testResults);
|
|
24
|
+
const history = [...historyDataPoints].sort((a, b) => b.timestamp - a.timestamp);
|
|
116
25
|
const labelName = groupBy.startsWith(CUSTOM_LABEL_NAME_PREFIX)
|
|
117
26
|
? groupBy.slice(CUSTOM_LABEL_NAME_PREFIX.length)
|
|
118
27
|
: groupBy;
|
|
119
28
|
const groupValuesSet = new Set(groupValues ?? []);
|
|
120
|
-
const
|
|
121
|
-
const keys = {};
|
|
29
|
+
const groups = new Map();
|
|
122
30
|
const hashes = createHashStorage();
|
|
123
31
|
const skipStatuses = new Set(skipStatusesList);
|
|
124
32
|
for (const tr of testResults) {
|
|
125
|
-
if (!tr.
|
|
33
|
+
if (!SIGNIFICANT_STATUSES.has(tr.status) || skipStatuses.has(tr.status)) {
|
|
126
34
|
continue;
|
|
127
35
|
}
|
|
128
|
-
|
|
36
|
+
const labelValue = tr.labels?.find((label) => label.name === labelName)?.value;
|
|
37
|
+
if (!labelValue || (groupValuesSet.size > 0 && !groupValuesSet.has(labelValue))) {
|
|
129
38
|
continue;
|
|
130
39
|
}
|
|
131
|
-
|
|
40
|
+
const flaky = tr.sourceMetadata?.reportedFlaky === true
|
|
41
|
+
? true
|
|
42
|
+
: getTestFlakiness(tr, history.map((point) => lookup(point, tr)), { historyDepth: limit, stabilizationPeriod });
|
|
43
|
+
if (flaky === undefined) {
|
|
132
44
|
continue;
|
|
133
45
|
}
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
46
|
+
const id = hashes.get(labelValue);
|
|
47
|
+
let counts = groups.get(id);
|
|
48
|
+
if (!counts) {
|
|
49
|
+
counts = { stable: 0, assessed: 0 };
|
|
50
|
+
groups.set(id, counts);
|
|
51
|
+
chart.keys[id] = labelValue;
|
|
137
52
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
continue;
|
|
53
|
+
counts.assessed++;
|
|
54
|
+
if (!flaky) {
|
|
55
|
+
counts.stable++;
|
|
142
56
|
}
|
|
143
|
-
const labelValueHash = hashes.get(labelValue);
|
|
144
|
-
keys[labelValueHash] = labelValue;
|
|
145
|
-
stabilityScoresByGroup.get(labelValueHash).push(stabilityScore);
|
|
146
57
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}),
|
|
153
|
-
keys,
|
|
154
|
-
type: ChartType.StabilityDistribution,
|
|
155
|
-
title,
|
|
156
|
-
threshold,
|
|
157
|
-
};
|
|
58
|
+
chart.data = [...groups].map(([id, counts]) => ({
|
|
59
|
+
id,
|
|
60
|
+
stabilityRate: Math.floor((counts.stable * 10000) / counts.assessed) / 100,
|
|
61
|
+
}));
|
|
62
|
+
return chart;
|
|
158
63
|
};
|
package/dist/charts/index.d.ts
CHANGED
package/dist/charts/index.js
CHANGED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function normalizeAttachmentContentType(type: string): string;
|
|
2
|
+
export declare function normalizeAttachmentContentType(type?: null | undefined): undefined;
|
|
3
|
+
export declare function normalizeAttachmentContentType(type?: string | null): string | undefined;
|
|
4
|
+
export declare const isJsonAttachmentContentType: (type: string) => boolean;
|
|
5
|
+
export declare const isHtmlAttachmentContentType: (type: string) => boolean;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function normalizeAttachmentContentType(type) {
|
|
2
|
+
return type?.split(";")[0].trim().toLowerCase();
|
|
3
|
+
}
|
|
4
|
+
export const isJsonAttachmentContentType = (type) => {
|
|
5
|
+
const normalized = normalizeAttachmentContentType(type);
|
|
6
|
+
return normalized === "application/json" || normalized === "text/json" || normalized.endsWith("+json");
|
|
7
|
+
};
|
|
8
|
+
export const isHtmlAttachmentContentType = (type) => {
|
|
9
|
+
const normalized = normalizeAttachmentContentType(type);
|
|
10
|
+
return normalized === "text/html" || normalized === "application/xhtml+xml";
|
|
11
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export declare const HTTP_EXCHANGE_REDACTED_VALUE = "__ALLURE_REDACTED__";
|
|
2
|
+
export type HttpPair = {
|
|
3
|
+
name: string;
|
|
4
|
+
value: string;
|
|
5
|
+
masked: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type HttpCookie = HttpPair & {
|
|
8
|
+
domain: string;
|
|
9
|
+
expires: string;
|
|
10
|
+
httpOnly: boolean;
|
|
11
|
+
maxAge?: number;
|
|
12
|
+
path: string;
|
|
13
|
+
sameSite: string;
|
|
14
|
+
secure: boolean;
|
|
15
|
+
};
|
|
16
|
+
export type HttpStream = {
|
|
17
|
+
type: string;
|
|
18
|
+
complete: string;
|
|
19
|
+
chunkCount?: number;
|
|
20
|
+
};
|
|
21
|
+
export type HttpBodyPart = {
|
|
22
|
+
name: string;
|
|
23
|
+
fileName: string;
|
|
24
|
+
headers: HttpPair[];
|
|
25
|
+
contentType: string;
|
|
26
|
+
encoding: string;
|
|
27
|
+
value: string;
|
|
28
|
+
hasValue: boolean;
|
|
29
|
+
size?: number;
|
|
30
|
+
truncated: boolean;
|
|
31
|
+
};
|
|
32
|
+
export type HttpBody = {
|
|
33
|
+
contentType: string;
|
|
34
|
+
encoding: string;
|
|
35
|
+
value: string;
|
|
36
|
+
hasValue: boolean;
|
|
37
|
+
size?: number;
|
|
38
|
+
truncated: boolean;
|
|
39
|
+
form: HttpPair[];
|
|
40
|
+
parts: HttpBodyPart[];
|
|
41
|
+
stream: HttpStream | null;
|
|
42
|
+
};
|
|
43
|
+
export type HttpRequest = {
|
|
44
|
+
method: string;
|
|
45
|
+
url: string;
|
|
46
|
+
httpVersion: string;
|
|
47
|
+
headers: HttpPair[];
|
|
48
|
+
cookies: HttpCookie[];
|
|
49
|
+
query: HttpPair[];
|
|
50
|
+
body: HttpBody | null;
|
|
51
|
+
trailers: HttpPair[];
|
|
52
|
+
};
|
|
53
|
+
export type HttpInformationalResponse = {
|
|
54
|
+
status: string;
|
|
55
|
+
reason: string;
|
|
56
|
+
headers: HttpPair[];
|
|
57
|
+
};
|
|
58
|
+
export type HttpResponse = {
|
|
59
|
+
status: string;
|
|
60
|
+
reason: string;
|
|
61
|
+
httpVersion: string;
|
|
62
|
+
headers: HttpPair[];
|
|
63
|
+
cookies: HttpCookie[];
|
|
64
|
+
body: HttpBody | null;
|
|
65
|
+
trailers: HttpPair[];
|
|
66
|
+
informationalResponses: HttpInformationalResponse[];
|
|
67
|
+
};
|
|
68
|
+
export type HttpError = {
|
|
69
|
+
name: string;
|
|
70
|
+
message: string;
|
|
71
|
+
stack: string;
|
|
72
|
+
};
|
|
73
|
+
export type NormalizedHttpPayload = {
|
|
74
|
+
request: HttpRequest | null;
|
|
75
|
+
response: HttpResponse | null;
|
|
76
|
+
error: HttpError | null;
|
|
77
|
+
durationMs: string;
|
|
78
|
+
};
|
|
79
|
+
export declare const normalizeHttpExchangePayload: (payload: unknown) => NormalizedHttpPayload;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
export const HTTP_EXCHANGE_REDACTED_VALUE = "__ALLURE_REDACTED__";
|
|
2
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
+
const toOptionalString = (value) => value === null || typeof value === "undefined" ? "" : String(value);
|
|
4
|
+
const toFiniteNumber = (value) => {
|
|
5
|
+
const num = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : NaN;
|
|
6
|
+
return Number.isFinite(num) ? num : undefined;
|
|
7
|
+
};
|
|
8
|
+
const headerValue = (headers, name) => {
|
|
9
|
+
const normalizedName = name.toLowerCase();
|
|
10
|
+
return headers.find((header) => header.name.toLowerCase() === normalizedName)?.value ?? "";
|
|
11
|
+
};
|
|
12
|
+
const normalizeArray = (value, normalize) => Array.isArray(value) ? value.map(normalize).filter((item) => item !== null) : [];
|
|
13
|
+
const normalizePair = (value) => {
|
|
14
|
+
if (!isRecord(value)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const name = toOptionalString(value.name).trim();
|
|
18
|
+
const pairValue = toOptionalString(value.value);
|
|
19
|
+
const masked = pairValue === HTTP_EXCHANGE_REDACTED_VALUE;
|
|
20
|
+
if (!name && !pairValue) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return { name, value: pairValue, masked };
|
|
24
|
+
};
|
|
25
|
+
const normalizePairs = (value) => normalizeArray(value, normalizePair);
|
|
26
|
+
const normalizeCookie = (value) => {
|
|
27
|
+
if (!isRecord(value)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const pair = normalizePair(value);
|
|
31
|
+
if (!pair) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
...pair,
|
|
36
|
+
domain: toOptionalString(value.domain).trim(),
|
|
37
|
+
expires: toOptionalString(value.expires).trim(),
|
|
38
|
+
httpOnly: value.httpOnly === true,
|
|
39
|
+
maxAge: toFiniteNumber(value.maxAge),
|
|
40
|
+
path: toOptionalString(value.path).trim(),
|
|
41
|
+
sameSite: toOptionalString(value.sameSite).trim(),
|
|
42
|
+
secure: value.secure === true,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const normalizeCookies = (value) => normalizeArray(value, normalizeCookie);
|
|
46
|
+
const normalizeStream = (value) => {
|
|
47
|
+
if (!isRecord(value)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
type: toOptionalString(value.type).trim(),
|
|
52
|
+
complete: typeof value.complete === "boolean" ? String(value.complete) : "",
|
|
53
|
+
chunkCount: toFiniteNumber(value.chunkCount),
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const normalizeBodyPart = (value) => {
|
|
57
|
+
if (!isRecord(value)) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const headers = normalizePairs(value.headers);
|
|
61
|
+
const hasValue = typeof value.value !== "undefined" && value.value !== null;
|
|
62
|
+
return {
|
|
63
|
+
name: toOptionalString(value.name).trim(),
|
|
64
|
+
fileName: toOptionalString(value.fileName).trim(),
|
|
65
|
+
headers,
|
|
66
|
+
contentType: toOptionalString(value.contentType).trim() || headerValue(headers, "content-type"),
|
|
67
|
+
encoding: toOptionalString(value.encoding).trim().toLowerCase() || "utf8",
|
|
68
|
+
value: hasValue ? String(value.value) : "",
|
|
69
|
+
hasValue,
|
|
70
|
+
size: toFiniteNumber(value.size),
|
|
71
|
+
truncated: value.truncated === true,
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
const normalizeBodyParts = (value) => normalizeArray(value, normalizeBodyPart);
|
|
75
|
+
const normalizeBody = (value, fallbackContentType = "") => {
|
|
76
|
+
if (!isRecord(value)) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const hasValue = typeof value.value !== "undefined" && value.value !== null;
|
|
80
|
+
return {
|
|
81
|
+
contentType: toOptionalString(value.contentType).trim() || fallbackContentType,
|
|
82
|
+
encoding: toOptionalString(value.encoding).trim().toLowerCase() || "utf8",
|
|
83
|
+
value: hasValue ? String(value.value) : "",
|
|
84
|
+
hasValue,
|
|
85
|
+
size: toFiniteNumber(value.size),
|
|
86
|
+
truncated: value.truncated === true,
|
|
87
|
+
form: normalizePairs(value.form),
|
|
88
|
+
parts: normalizeBodyParts(value.parts),
|
|
89
|
+
stream: normalizeStream(value.stream),
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
const normalizeRequest = (value) => {
|
|
93
|
+
if (!isRecord(value)) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const headers = normalizePairs(value.headers);
|
|
97
|
+
return {
|
|
98
|
+
method: toOptionalString(value.method).trim().toUpperCase() || "GET",
|
|
99
|
+
url: toOptionalString(value.url).trim(),
|
|
100
|
+
httpVersion: toOptionalString(value.httpVersion).trim(),
|
|
101
|
+
headers,
|
|
102
|
+
cookies: normalizeCookies(value.cookies),
|
|
103
|
+
query: normalizePairs(value.query),
|
|
104
|
+
body: normalizeBody(value.body, headerValue(headers, "content-type")),
|
|
105
|
+
trailers: normalizePairs(value.trailers),
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
const normalizeInformationalResponse = (value) => {
|
|
109
|
+
if (!isRecord(value)) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
status: toOptionalString(value.status).trim(),
|
|
114
|
+
reason: toOptionalString(value.statusText).trim(),
|
|
115
|
+
headers: normalizePairs(value.headers),
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
const normalizeInformationalResponses = (value) => normalizeArray(value, normalizeInformationalResponse);
|
|
119
|
+
const normalizeResponse = (value) => {
|
|
120
|
+
if (!isRecord(value)) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const headers = normalizePairs(value.headers);
|
|
124
|
+
return {
|
|
125
|
+
status: toOptionalString(value.status).trim(),
|
|
126
|
+
reason: toOptionalString(value.statusText).trim(),
|
|
127
|
+
httpVersion: toOptionalString(value.httpVersion).trim(),
|
|
128
|
+
headers,
|
|
129
|
+
cookies: normalizeCookies(value.cookies),
|
|
130
|
+
body: normalizeBody(value.body, headerValue(headers, "content-type")),
|
|
131
|
+
trailers: normalizePairs(value.trailers),
|
|
132
|
+
informationalResponses: normalizeInformationalResponses(value.informationalResponses),
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
const normalizeError = (value) => {
|
|
136
|
+
if (!isRecord(value)) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const name = toOptionalString(value.name).trim();
|
|
140
|
+
const message = toOptionalString(value.message).trim();
|
|
141
|
+
const stack = toOptionalString(value.stack).trim();
|
|
142
|
+
if (!name && !message && !stack) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
return { name, message, stack };
|
|
146
|
+
};
|
|
147
|
+
export const normalizeHttpExchangePayload = (payload) => {
|
|
148
|
+
if (!isRecord(payload)) {
|
|
149
|
+
return { request: null, response: null, error: null, durationMs: "" };
|
|
150
|
+
}
|
|
151
|
+
const start = toFiniteNumber(payload.start);
|
|
152
|
+
const stop = toFiniteNumber(payload.stop);
|
|
153
|
+
const durationMs = start !== undefined && stop !== undefined && stop >= start ? `${stop - start} ms` : "";
|
|
154
|
+
return {
|
|
155
|
+
request: normalizeRequest(payload.request),
|
|
156
|
+
response: normalizeResponse(payload.response),
|
|
157
|
+
error: normalizeError(payload.error),
|
|
158
|
+
durationMs,
|
|
159
|
+
};
|
|
160
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -19,3 +19,6 @@ export * from "./treeSubtreeToggle.js";
|
|
|
19
19
|
export * from "./subtreeExpansion.js";
|
|
20
20
|
export * from "./hotkeys/index.js";
|
|
21
21
|
export * from "./treeNavigation/index.js";
|
|
22
|
+
export * from "./platform.js";
|
|
23
|
+
export * from "./contentTypes.js";
|
|
24
|
+
export * from "./httpAttachments.js";
|
package/dist/index.js
CHANGED
|
@@ -19,3 +19,6 @@ export * from "./treeSubtreeToggle.js";
|
|
|
19
19
|
export * from "./subtreeExpansion.js";
|
|
20
20
|
export * from "./hotkeys/index.js";
|
|
21
21
|
export * from "./treeNavigation/index.js";
|
|
22
|
+
export * from "./platform.js";
|
|
23
|
+
export * from "./contentTypes.js";
|
|
24
|
+
export * from "./httpAttachments.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const testPlatform: (re: RegExp) => boolean;
|
package/dist/platform.js
ADDED
|
@@ -14,6 +14,3 @@ export declare const currentUrl: import("@preact/signals-core").ReadonlySignal<{
|
|
|
14
14
|
export declare const getParamValue: (key: string) => string | null;
|
|
15
15
|
export declare const getParamValues: (key: string) => string[];
|
|
16
16
|
export declare const hasParam: (key: string) => boolean;
|
|
17
|
-
export declare const getParamValueComputed: (key: string) => import("@preact/signals-core").ReadonlySignal<string | null>;
|
|
18
|
-
export declare const getParamValuesComputed: (key: string) => import("@preact/signals-core").ReadonlySignal<string[]>;
|
|
19
|
-
export declare const hasParamComputed: (key: string) => import("@preact/signals-core").ReadonlySignal<boolean>;
|
package/dist/stores/url/store.js
CHANGED
|
@@ -40,6 +40,3 @@ export const currentUrl = computed(() => {
|
|
|
40
40
|
export const getParamValue = (key) => urlSearchParams.value.get(key);
|
|
41
41
|
export const getParamValues = (key) => urlSearchParams.value.getAll(key);
|
|
42
42
|
export const hasParam = (key) => urlSearchParams.value.has(key);
|
|
43
|
-
export const getParamValueComputed = (key) => computed(() => getParamValue(key));
|
|
44
|
-
export const getParamValuesComputed = (key) => computed(() => getParamValues(key));
|
|
45
|
-
export const hasParamComputed = (key) => computed(() => hasParam(key));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allurereport/web-commons",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.22.0",
|
|
4
4
|
"description": "Collection of utilities used across the web Allure reports",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"allure",
|
|
@@ -21,16 +21,16 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "run clean && tsc --project ./tsconfig.json",
|
|
23
23
|
"clean": "rimraf ./dist",
|
|
24
|
-
"test": "
|
|
24
|
+
"test": "rimraf out && vp test run",
|
|
25
25
|
"test:unit": "yarn test",
|
|
26
|
-
"lint": "
|
|
27
|
-
"lint:fix": "
|
|
26
|
+
"lint": "vp lint --import-plugin src test features stories",
|
|
27
|
+
"lint:fix": "vp lint --import-plugin --fix src test features stories"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@allurereport/aql": "3.
|
|
31
|
-
"@allurereport/charts-api": "3.
|
|
32
|
-
"@allurereport/core-api": "3.
|
|
33
|
-
"@allurereport/plugin-api": "3.
|
|
30
|
+
"@allurereport/aql": "3.22.0",
|
|
31
|
+
"@allurereport/charts-api": "3.22.0",
|
|
32
|
+
"@allurereport/core-api": "3.22.0",
|
|
33
|
+
"@allurereport/plugin-api": "3.22.0",
|
|
34
34
|
"@preact/signals": "^2.6.1",
|
|
35
35
|
"@preact/signals-core": "^1.12.2",
|
|
36
36
|
"ansi-to-html": "^0.7.2",
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"nanoid": "^5.1.16"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@allurereport/
|
|
44
|
+
"@allurereport/common-config": "3.22.0",
|
|
45
45
|
"@types/d3-interpolate": "^3.0.4",
|
|
46
46
|
"@types/d3-scale": "^4.0.9",
|
|
47
47
|
"@types/d3-shape": "^3.1.8",
|
|
48
|
-
"@vitest/coverage-istanbul": "
|
|
48
|
+
"@vitest/coverage-istanbul": "5.0.4",
|
|
49
49
|
"@vitest/runner": "^2",
|
|
50
50
|
"allure-js-commons": "^3",
|
|
51
51
|
"allure-vitest": "^3",
|
|
@@ -53,6 +53,8 @@
|
|
|
53
53
|
"rimraf": "^6",
|
|
54
54
|
"tslib": "^2.7.0",
|
|
55
55
|
"typescript": "^5",
|
|
56
|
-
"
|
|
56
|
+
"vite": "@voidzero-dev/vite-plus-core@1.2.0",
|
|
57
|
+
"vite-plus": "1.2.0",
|
|
58
|
+
"vitest": "5.0.4"
|
|
57
59
|
}
|
|
58
60
|
}
|