@allurereport/web-commons 3.21.0 → 3.22.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.
@@ -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.split(";")[0].trim().toLowerCase() === PLAYWRIGHT_TRACE_CONTENT_TYPE
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.split(";")[0].trim().toLowerCase());
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?.split(";")[0].trim().toLowerCase();
200
+ const normalizedType = normalizeAttachmentContentType(type);
200
201
  switch (normalizedType) {
201
202
  case "image/bmp":
202
203
  case "image/gif":
@@ -0,0 +1,2 @@
1
+ import { type ChartOptions } from "@allurereport/charts-api";
2
+ export declare const validateChartsOptions: (charts: ChartOptions[]) => void;
@@ -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, createMapWithDefault } from "./utils.js";
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 = DEFAULT_LIMIT, stabilizationPeriod = DEFAULT_STABILIZATION_PERIOD, threshold = DEFAULT_THRESHOLD, skipStatuses: skipStatusesList = NON_SIGNIFICANT_STATUSES, groupBy = DEFAULT_GROUP_BY, groupValues = [], } = options;
103
- const { testResults, historyDataPoints } = storeData;
104
- const lookupHistoryTestResult = createHistoryTestResultLookup(storeData.allTestResults ?? testResults);
105
- const effectiveStabilizationPeriod = Math.min(stabilizationPeriod, limit);
106
- if (historyDataPoints.length < effectiveStabilizationPeriod) {
107
- return {
108
- data: [],
109
- keys: {},
110
- type: ChartType.StabilityDistribution,
111
- title,
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 limitedHistoryDataPoints = historyDataPoints.slice(0, limit).sort((a, b) => a.timestamp - b.timestamp);
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 stabilityScoresByGroup = createMapWithDefault([]);
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.retryHash) {
33
+ if (!SIGNIFICANT_STATUSES.has(tr.status) || skipStatuses.has(tr.status)) {
126
34
  continue;
127
35
  }
128
- if (!isSignificantStatus(tr.status)) {
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
- if (skipStatuses.has(tr.status)) {
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 labelValue = getTrLabelValue(tr, labelName);
135
- if (!labelValue || (groupValuesSet.size > 0 && !groupValuesSet.has(labelValue))) {
136
- continue;
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
- const statusSequence = getStatusSequence(limitedHistoryDataPoints, tr, lookupHistoryTestResult);
139
- const stabilityScore = getStabilityScore(statusSequence, limit, effectiveStabilizationPeriod);
140
- if (stabilityScore === undefined) {
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
- return {
148
- data: stabilityScoresByGroup.entries.map(([id, scores]) => {
149
- const avg = scores.length > 0 ? scores.reduce((a, b) => a + b, 0) / scores.length : 0;
150
- const stabilityRate = Math.floor(avg * 10000) / 100;
151
- return { id, stabilityRate };
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
  };
@@ -1,4 +1,5 @@
1
1
  export * from "./utils.js";
2
+ export * from "./config.js";
2
3
  export type * from "./types.js";
3
4
  export * from "./colors.js";
4
5
  export * from "./chart-utils.js";
@@ -1,4 +1,5 @@
1
1
  export * from "./utils.js";
2
+ export * from "./config.js";
2
3
  export * from "./colors.js";
3
4
  export * from "./chart-utils.js";
4
5
  export * from "./line.js";
@@ -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;
@@ -0,0 +1,8 @@
1
+ export const testPlatform = (re) => {
2
+ if (typeof window === "undefined") {
3
+ return false;
4
+ }
5
+ const navigator = window?.navigator;
6
+ const platform = navigator?.userAgentData?.platform ?? navigator?.platform;
7
+ return platform ? re.test(platform) : false;
8
+ };
@@ -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>;
@@ -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.21.0",
3
+ "version": "3.22.1",
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": "vitest run",
24
+ "test": "rimraf out && vp test run",
25
25
  "test:unit": "yarn test",
26
- "lint": "oxlint --import-plugin src test features stories",
27
- "lint:fix": "oxlint --import-plugin --fix src test features stories"
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.21.0",
31
- "@allurereport/charts-api": "3.21.0",
32
- "@allurereport/core-api": "3.21.0",
33
- "@allurereport/plugin-api": "3.21.0",
30
+ "@allurereport/aql": "3.22.1",
31
+ "@allurereport/charts-api": "3.22.1",
32
+ "@allurereport/core-api": "3.22.1",
33
+ "@allurereport/plugin-api": "3.22.1",
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/test-config": "3.21.0",
44
+ "@allurereport/common-config": "3.22.1",
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": "^4.1.0",
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
- "vitest": "^4.1.0"
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
  }