@allurereport/web-awesome 3.0.0 → 3.0.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.
Files changed (76) hide show
  1. package/dist/multi/{173.app-9931797d1602fc52db5b.js → 173.app-bae2a0fe5738d77cd976.js} +1 -1
  2. package/dist/multi/174.app-bae2a0fe5738d77cd976.js +1 -0
  3. package/dist/multi/{252.app-9931797d1602fc52db5b.js → 252.app-bae2a0fe5738d77cd976.js} +1 -1
  4. package/dist/multi/{282.app-9931797d1602fc52db5b.js → 282.app-bae2a0fe5738d77cd976.js} +1 -1
  5. package/dist/multi/{29.app-9931797d1602fc52db5b.js → 29.app-bae2a0fe5738d77cd976.js} +1 -1
  6. package/dist/multi/{416.app-9931797d1602fc52db5b.js → 416.app-bae2a0fe5738d77cd976.js} +1 -1
  7. package/dist/multi/{527.app-9931797d1602fc52db5b.js → 527.app-bae2a0fe5738d77cd976.js} +1 -1
  8. package/dist/multi/{600.app-9931797d1602fc52db5b.js → 600.app-bae2a0fe5738d77cd976.js} +1 -1
  9. package/dist/multi/{605.app-9931797d1602fc52db5b.js → 605.app-bae2a0fe5738d77cd976.js} +1 -1
  10. package/dist/multi/{638.app-9931797d1602fc52db5b.js → 638.app-bae2a0fe5738d77cd976.js} +1 -1
  11. package/dist/multi/{672.app-9931797d1602fc52db5b.js → 672.app-bae2a0fe5738d77cd976.js} +1 -1
  12. package/dist/multi/{686.app-9931797d1602fc52db5b.js → 686.app-bae2a0fe5738d77cd976.js} +1 -1
  13. package/dist/multi/{725.app-9931797d1602fc52db5b.js → 725.app-bae2a0fe5738d77cd976.js} +1 -1
  14. package/dist/multi/{741.app-9931797d1602fc52db5b.js → 741.app-bae2a0fe5738d77cd976.js} +1 -1
  15. package/dist/multi/{755.app-9931797d1602fc52db5b.js → 755.app-bae2a0fe5738d77cd976.js} +1 -1
  16. package/dist/multi/{894.app-9931797d1602fc52db5b.js → 894.app-bae2a0fe5738d77cd976.js} +1 -1
  17. package/dist/multi/{91.app-9931797d1602fc52db5b.js → 91.app-bae2a0fe5738d77cd976.js} +1 -1
  18. package/dist/multi/{943.app-9931797d1602fc52db5b.js → 943.app-bae2a0fe5738d77cd976.js} +1 -1
  19. package/dist/multi/{980.app-9931797d1602fc52db5b.js → 980.app-bae2a0fe5738d77cd976.js} +1 -1
  20. package/dist/multi/app-bae2a0fe5738d77cd976.js +2 -0
  21. package/dist/multi/manifest.json +21 -21
  22. package/dist/multi/{styles-8fe37354d1c2270c691e.css → styles-bbf68b2ba63c38b53c38.css} +3 -3
  23. package/dist/single/app-996d3b5869f8fc942b66.js +2 -0
  24. package/dist/single/manifest.json +1 -1
  25. package/package.json +8 -8
  26. package/src/assets/scss/palette.scss +102 -102
  27. package/src/components/ReportBody/Filters.tsx +84 -33
  28. package/src/components/ReportBody/HeaderActions.tsx +2 -2
  29. package/src/components/ReportBody/SortBy.tsx +4 -7
  30. package/src/components/ReportBody/index.tsx +12 -17
  31. package/src/components/ReportTabs/index.tsx +37 -0
  32. package/src/components/SplitLayout/index.tsx +0 -2
  33. package/src/components/TestResult/TestStepsEmpty/index.tsx +1 -7
  34. package/src/components/TestResult/TrEmpty/index.tsx +1 -7
  35. package/src/components/TestResult/TrError/index.tsx +9 -2
  36. package/src/components/TestResult/TrSteps/TrStep.tsx +3 -3
  37. package/src/components/Tree/index.tsx +9 -17
  38. package/src/index.tsx +0 -1
  39. package/src/locales/az.json +3 -1
  40. package/src/locales/de.json +3 -1
  41. package/src/locales/en.json +4 -2
  42. package/src/locales/es.json +3 -1
  43. package/src/locales/fr.json +3 -1
  44. package/src/locales/he.json +3 -1
  45. package/src/locales/hy.json +3 -1
  46. package/src/locales/it.json +3 -1
  47. package/src/locales/ja.json +3 -1
  48. package/src/locales/ka.json +3 -1
  49. package/src/locales/kr.json +3 -1
  50. package/src/locales/nl.json +3 -1
  51. package/src/locales/pl.json +3 -1
  52. package/src/locales/pt.json +3 -1
  53. package/src/locales/ru.json +3 -1
  54. package/src/locales/sv.json +3 -1
  55. package/src/locales/tr.json +3 -1
  56. package/src/locales/ua.json +3 -1
  57. package/src/locales/zh.json +3 -1
  58. package/src/stores/tree.ts +37 -121
  59. package/src/stores/treeFilters/actions.ts +67 -0
  60. package/src/stores/treeFilters/constants.ts +7 -0
  61. package/src/stores/treeFilters/index.ts +3 -0
  62. package/src/stores/treeFilters/store.ts +73 -0
  63. package/src/stores/treeFilters/types.ts +12 -0
  64. package/src/utils/persist.ts +23 -0
  65. package/src/utils/tree.ts +12 -5
  66. package/src/utils/treeFilters.ts +16 -4
  67. package/test/stores/treeFilters.test.ts +302 -0
  68. package/test/utils/treeFilters.test.ts +145 -0
  69. package/types.d.ts +2 -0
  70. package/dist/multi/174.app-9931797d1602fc52db5b.js +0 -1
  71. package/dist/multi/app-9931797d1602fc52db5b.js +0 -2
  72. package/dist/single/app-6199dc1c2fd3bddc2526.js +0 -2
  73. package/src/components/Tabs/index.tsx +0 -62
  74. /package/dist/multi/{app-9931797d1602fc52db5b.js.LICENSE.txt → app-bae2a0fe5738d77cd976.js.LICENSE.txt} +0 -0
  75. /package/dist/single/{app-6199dc1c2fd3bddc2526.js.LICENSE.txt → app-996d3b5869f8fc942b66.js.LICENSE.txt} +0 -0
  76. /package/src/components/{Tabs → ReportTabs}/styles.scss +0 -0
@@ -0,0 +1,73 @@
1
+ import { batch, computed, effect, signal } from "@preact/signals";
2
+ import type { AwesomeStatus } from "types";
3
+ import { loadFromLocalStorage } from "@/utils/loadFromLocalStorage";
4
+ import { persist } from "@/utils/persist";
5
+ import { transitionFiltersList } from "./constants";
6
+ import type { TreeDirection, TreeFilters, TreeFiltersState, TreeSortBy } from "./types";
7
+
8
+ export const treeQuery = signal<string>("");
9
+ export const treeStatus = signal<AwesomeStatus>("total");
10
+ export const treeSortBy = signal<TreeSortBy>("order");
11
+ export const treeDirection = signal<TreeDirection>("asc");
12
+ export const treeFilter = signal<Record<TreeFilters, boolean>>({
13
+ flaky: false,
14
+ retry: false,
15
+ new: false,
16
+ fixed: false,
17
+ regressed: false,
18
+ malfunctioned: false,
19
+ });
20
+
21
+ const initialized = signal(false);
22
+
23
+ const init = () => {
24
+ const initialState = loadFromLocalStorage<TreeFiltersState>("treeFilters", {
25
+ query: "",
26
+ status: "total",
27
+ filter: {
28
+ flaky: false,
29
+ retry: false,
30
+ new: false,
31
+ fixed: false,
32
+ regressed: false,
33
+ malfunctioned: false,
34
+ },
35
+ sortBy: "order",
36
+ direction: "asc",
37
+ });
38
+
39
+ batch(() => {
40
+ treeQuery.value = initialState.query;
41
+ treeStatus.value = initialState.status;
42
+ treeSortBy.value = initialState.sortBy;
43
+ treeDirection.value = initialState.direction;
44
+ treeFilter.value = initialState.filter;
45
+ initialized.value = true;
46
+ });
47
+ };
48
+
49
+ init();
50
+
51
+ const treeFiltersState = computed(() => ({
52
+ query: treeQuery.value,
53
+ status: treeStatus.value,
54
+ sortBy: treeSortBy.value,
55
+ direction: treeDirection.value,
56
+ filter: treeFilter.value,
57
+ }));
58
+
59
+ effect(() => {
60
+ if (!initialized.value) {
61
+ return;
62
+ }
63
+
64
+ persist(["treeFilters", treeFiltersState.value]);
65
+ });
66
+
67
+ export const transitionFilters = computed(() =>
68
+ transitionFiltersList.map((transition) => [transition, treeFilter.value[transition]] as const),
69
+ );
70
+
71
+ export const testTypeFilters = computed(() =>
72
+ (["flaky", "retry"] as const).map((testType) => [testType, treeFilter.value[testType]] as const),
73
+ );
@@ -0,0 +1,12 @@
1
+ import type { AwesomeStatus } from "types";
2
+
3
+ export type TreeSortBy = "order" | "duration" | "status" | "alphabet";
4
+ export type TreeDirection = "asc" | "desc";
5
+ export type TreeFilters = "flaky" | "retry" | "new" | "fixed" | "regressed" | "malfunctioned";
6
+ export type TreeFiltersState = {
7
+ query: string;
8
+ status: AwesomeStatus;
9
+ filter: Record<TreeFilters, boolean>;
10
+ sortBy: TreeSortBy;
11
+ direction: TreeDirection;
12
+ };
@@ -0,0 +1,23 @@
1
+ class AllurePersistError extends Error {
2
+ constructor(
3
+ message: string,
4
+ public readonly originalError?: Error,
5
+ ) {
6
+ super(message);
7
+ this.name = "AllurePersistError";
8
+ }
9
+
10
+ get message(): string {
11
+ return `${this.name}: ${this.message}${this.originalError ? `\n${this.originalError.message}` : ""}`;
12
+ }
13
+ }
14
+
15
+ export const persist = <T>(pair: [string, T], storage: Storage = localStorage) => {
16
+ const [key, value] = pair;
17
+ try {
18
+ storage.setItem(key, JSON.stringify(value));
19
+ } catch (e) {
20
+ // eslint-disable-next-line no-console
21
+ console.error(new AllurePersistError(`Failed to persist ${key} to ${storage.name}`, e as Error));
22
+ }
23
+ };
package/src/utils/tree.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { RecursiveTree } from "@allurereport/web-components/global";
2
2
  import type { AwesomeTreeLeaf } from "types";
3
3
 
4
- type Localizer = (data: string) => string;
4
+ type Localizer = (data: string, params?: Record<string, unknown>) => string;
5
5
 
6
6
  type Localizers = {
7
7
  tooltip: Localizer;
@@ -9,10 +9,17 @@ type Localizers = {
9
9
 
10
10
  export const createLeafLocalizer =
11
11
  (t: Localizers) =>
12
- (leaf: AwesomeTreeLeaf): AwesomeTreeLeaf => ({
13
- ...leaf,
14
- transitionTooltip: t.tooltip(leaf.transition),
15
- });
12
+ (leaf: AwesomeTreeLeaf): AwesomeTreeLeaf => {
13
+ const tooltips = {
14
+ transition: t.tooltip(leaf.transition),
15
+ flaky: leaf.flaky && t.tooltip("flaky"),
16
+ retries: leaf.retriesCount && t.tooltip("retries", { count: leaf.retriesCount }),
17
+ };
18
+ return {
19
+ ...leaf,
20
+ tooltips,
21
+ };
22
+ };
16
23
 
17
24
  export const createTreeLocalizer =
18
25
  (t: Localizers) =>
@@ -11,11 +11,23 @@ import {
11
11
  ordinal,
12
12
  reverse,
13
13
  } from "@allurereport/core-api";
14
- import type { TreeFiltersState, TreeSortBy } from "@/stores/tree";
14
+ import type { TreeFiltersState, TreeSortBy } from "@/stores/treeFilters";
15
15
  import type { AwesomeRecursiveTree, AwesomeTree, AwesomeTreeGroup, AwesomeTreeLeaf } from "../../types";
16
16
 
17
+ const matchesName = (name: string, query: string) => {
18
+ return name.toLocaleLowerCase().includes(query.toLocaleLowerCase());
19
+ };
20
+
21
+ const matchesNodeId = (nodeId: string, query: string) => {
22
+ return nodeId.toLowerCase() === query.toLocaleLowerCase();
23
+ };
24
+
17
25
  export const isIncluded = (leaf: TreeLeaf<AwesomeTreeLeaf>, filterOptions: TreeFiltersState) => {
18
- const queryMatched = !filterOptions?.query || leaf.name.toLowerCase().includes(filterOptions.query.toLowerCase());
26
+ const queryMatched =
27
+ !filterOptions?.query ||
28
+ matchesName(leaf.name, filterOptions.query) ||
29
+ matchesNodeId(leaf.nodeId, filterOptions.query);
30
+
19
31
  const statusMatched =
20
32
  !filterOptions?.status || filterOptions?.status === "total" || leaf.status === filterOptions.status;
21
33
  const flakyMatched = !filterOptions?.filter?.flaky || leaf.flaky;
@@ -23,7 +35,7 @@ export const isIncluded = (leaf: TreeLeaf<AwesomeTreeLeaf>, filterOptions: TreeF
23
35
  const newMatched = !filterOptions?.filter?.new || leaf.transition === "new";
24
36
  const fixedMatched = !filterOptions?.filter?.fixed || leaf.transition === "fixed";
25
37
  const regressedMatched = !filterOptions?.filter?.regressed || leaf.transition === "regressed";
26
- const malfuctionedMatched = !filterOptions?.filter?.malfunctioned || leaf.transition === "malfunctioned";
38
+ const malfunctionedMatched = !filterOptions?.filter?.malfunctioned || leaf.transition === "malfunctioned";
27
39
 
28
40
  return [
29
41
  queryMatched,
@@ -33,7 +45,7 @@ export const isIncluded = (leaf: TreeLeaf<AwesomeTreeLeaf>, filterOptions: TreeF
33
45
  newMatched,
34
46
  fixedMatched,
35
47
  regressedMatched,
36
- malfuctionedMatched,
48
+ malfunctionedMatched,
37
49
  ].every(Boolean);
38
50
  };
39
51
 
@@ -0,0 +1,302 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import {
3
+ clearTreeFilters,
4
+ setTestTypeFilter,
5
+ setTransitionFilter,
6
+ setTreeDirection,
7
+ setTreeQuery,
8
+ setTreeSortBy,
9
+ setTreeStatus,
10
+ treeDirection,
11
+ treeFilter,
12
+ treeQuery,
13
+ treeSortBy,
14
+ treeStatus,
15
+ } from "@/stores/treeFilters";
16
+
17
+ const defaultFilter = {
18
+ flaky: false,
19
+ retry: false,
20
+ new: false,
21
+ fixed: false,
22
+ regressed: false,
23
+ malfunctioned: false,
24
+ };
25
+
26
+ describe("stores > treeFilters", () => {
27
+ beforeEach(() => {
28
+ // Reset all signals to default state before each test
29
+ treeQuery.value = "";
30
+ treeStatus.value = "total";
31
+ treeSortBy.value = "order";
32
+ treeDirection.value = "asc";
33
+ treeFilter.value = { ...defaultFilter };
34
+ });
35
+
36
+ afterEach(() => {
37
+ vi.clearAllMocks();
38
+ });
39
+
40
+ describe("clearTreeFilters", () => {
41
+ it("should reset query, status and filters to default state", () => {
42
+ // Set some non-default values
43
+ treeQuery.value = "test query";
44
+ treeStatus.value = "passed";
45
+ treeFilter.value = {
46
+ flaky: true,
47
+ retry: true,
48
+ new: true,
49
+ fixed: true,
50
+ regressed: true,
51
+ malfunctioned: true,
52
+ };
53
+
54
+ clearTreeFilters();
55
+
56
+ expect(treeQuery.value).toBe("");
57
+ expect(treeStatus.value).toBe("total");
58
+ expect(treeFilter.value).toEqual(defaultFilter);
59
+ });
60
+
61
+ it("should not reset sortBy and direction", () => {
62
+ treeSortBy.value = "duration";
63
+ treeDirection.value = "desc";
64
+
65
+ clearTreeFilters();
66
+
67
+ expect(treeSortBy.value).toBe("duration");
68
+ expect(treeDirection.value).toBe("desc");
69
+ });
70
+ });
71
+
72
+ describe("setTreeQuery", () => {
73
+ it("should update query", () => {
74
+ setTreeQuery("search term");
75
+
76
+ expect(treeQuery.value).toBe("search term");
77
+ });
78
+
79
+ it("should update query to empty string", () => {
80
+ treeQuery.value = "some query";
81
+
82
+ setTreeQuery("");
83
+
84
+ expect(treeQuery.value).toBe("");
85
+ });
86
+ });
87
+
88
+ describe("setTreeStatus", () => {
89
+ it("should update status to passed", () => {
90
+ setTreeStatus("passed");
91
+
92
+ expect(treeStatus.value).toBe("passed");
93
+ });
94
+
95
+ it("should update status to failed", () => {
96
+ setTreeStatus("failed");
97
+
98
+ expect(treeStatus.value).toBe("failed");
99
+ });
100
+
101
+ it("should update status to broken", () => {
102
+ setTreeStatus("broken");
103
+
104
+ expect(treeStatus.value).toBe("broken");
105
+ });
106
+
107
+ it("should update status to skipped", () => {
108
+ setTreeStatus("skipped");
109
+
110
+ expect(treeStatus.value).toBe("skipped");
111
+ });
112
+
113
+ it("should update status to total", () => {
114
+ treeStatus.value = "passed";
115
+
116
+ setTreeStatus("total");
117
+
118
+ expect(treeStatus.value).toBe("total");
119
+ });
120
+ });
121
+
122
+ describe("setTreeSortBy", () => {
123
+ it("should update sortBy to duration", () => {
124
+ setTreeSortBy("duration");
125
+
126
+ expect(treeSortBy.value).toBe("duration");
127
+ });
128
+
129
+ it("should update sortBy to status", () => {
130
+ setTreeSortBy("status");
131
+
132
+ expect(treeSortBy.value).toBe("status");
133
+ });
134
+
135
+ it("should update sortBy to alphabet", () => {
136
+ setTreeSortBy("alphabet");
137
+
138
+ expect(treeSortBy.value).toBe("alphabet");
139
+ });
140
+
141
+ it("should update sortBy to order", () => {
142
+ treeSortBy.value = "duration";
143
+
144
+ setTreeSortBy("order");
145
+
146
+ expect(treeSortBy.value).toBe("order");
147
+ });
148
+ });
149
+
150
+ describe("setTreeDirection", () => {
151
+ it("should update direction to desc", () => {
152
+ setTreeDirection("desc");
153
+
154
+ expect(treeDirection.value).toBe("desc");
155
+ });
156
+
157
+ it("should update direction to asc", () => {
158
+ treeDirection.value = "desc";
159
+
160
+ setTreeDirection("asc");
161
+
162
+ expect(treeDirection.value).toBe("asc");
163
+ });
164
+ });
165
+
166
+ describe("setTestTypeFilter", () => {
167
+ it("should enable flaky filter", () => {
168
+ setTestTypeFilter("flaky", true);
169
+
170
+ expect(treeFilter.value.flaky).toBe(true);
171
+ });
172
+
173
+ it("should disable flaky filter", () => {
174
+ treeFilter.value = { ...defaultFilter, flaky: true };
175
+
176
+ setTestTypeFilter("flaky", false);
177
+
178
+ expect(treeFilter.value.flaky).toBe(false);
179
+ });
180
+
181
+ it("should enable retry filter", () => {
182
+ setTestTypeFilter("retry", true);
183
+
184
+ expect(treeFilter.value.retry).toBe(true);
185
+ });
186
+
187
+ it("should disable retry filter", () => {
188
+ treeFilter.value = { ...defaultFilter, retry: true };
189
+
190
+ setTestTypeFilter("retry", false);
191
+
192
+ expect(treeFilter.value.retry).toBe(false);
193
+ });
194
+
195
+ it("should enable both flaky and retry filters independently", () => {
196
+ setTestTypeFilter("flaky", true);
197
+ setTestTypeFilter("retry", true);
198
+
199
+ expect(treeFilter.value.flaky).toBe(true);
200
+ expect(treeFilter.value.retry).toBe(true);
201
+ });
202
+
203
+ it("should not affect transition filters", () => {
204
+ treeFilter.value = { ...defaultFilter, new: true };
205
+
206
+ setTestTypeFilter("flaky", true);
207
+
208
+ expect(treeFilter.value.new).toBe(true);
209
+ expect(treeFilter.value.flaky).toBe(true);
210
+ });
211
+ });
212
+
213
+ describe("setTransitionFilter", () => {
214
+ it("should enable new filter", () => {
215
+ setTransitionFilter("new", true);
216
+
217
+ expect(treeFilter.value.new).toBe(true);
218
+ });
219
+
220
+ it("should enable fixed filter", () => {
221
+ setTransitionFilter("fixed", true);
222
+
223
+ expect(treeFilter.value.fixed).toBe(true);
224
+ });
225
+
226
+ it("should enable regressed filter", () => {
227
+ setTransitionFilter("regressed", true);
228
+
229
+ expect(treeFilter.value.regressed).toBe(true);
230
+ });
231
+
232
+ it("should enable malfunctioned filter", () => {
233
+ setTransitionFilter("malfunctioned", true);
234
+
235
+ expect(treeFilter.value.malfunctioned).toBe(true);
236
+ });
237
+
238
+ it("should disable the previous transition when enabling a new one", () => {
239
+ setTransitionFilter("new", true);
240
+ expect(treeFilter.value.new).toBe(true);
241
+
242
+ setTransitionFilter("fixed", true);
243
+
244
+ expect(treeFilter.value.new).toBe(false);
245
+ expect(treeFilter.value.fixed).toBe(true);
246
+ expect(treeFilter.value.regressed).toBe(false);
247
+ expect(treeFilter.value.malfunctioned).toBe(false);
248
+ });
249
+
250
+ it("should disable all other transitions when enabling regressed", () => {
251
+ treeFilter.value = { ...defaultFilter, new: true, fixed: true };
252
+
253
+ setTransitionFilter("regressed", true);
254
+
255
+ expect(treeFilter.value.new).toBe(false);
256
+ expect(treeFilter.value.fixed).toBe(false);
257
+ expect(treeFilter.value.regressed).toBe(true);
258
+ expect(treeFilter.value.malfunctioned).toBe(false);
259
+ });
260
+
261
+ it("should allow only one transition to be enabled at a time", () => {
262
+ setTransitionFilter("new", true);
263
+ setTransitionFilter("fixed", true);
264
+ setTransitionFilter("regressed", true);
265
+ setTransitionFilter("malfunctioned", true);
266
+
267
+ expect(treeFilter.value.new).toBe(false);
268
+ expect(treeFilter.value.fixed).toBe(false);
269
+ expect(treeFilter.value.regressed).toBe(false);
270
+ expect(treeFilter.value.malfunctioned).toBe(true);
271
+ });
272
+
273
+ it("should disable the transition when value is false", () => {
274
+ treeFilter.value = { ...defaultFilter, new: true };
275
+
276
+ setTransitionFilter("new", false);
277
+
278
+ expect(treeFilter.value.new).toBe(false);
279
+ });
280
+
281
+ it("should disable all transitions when disabling the active one", () => {
282
+ setTransitionFilter("fixed", true);
283
+
284
+ setTransitionFilter("fixed", false);
285
+
286
+ expect(treeFilter.value.new).toBe(false);
287
+ expect(treeFilter.value.fixed).toBe(false);
288
+ expect(treeFilter.value.regressed).toBe(false);
289
+ expect(treeFilter.value.malfunctioned).toBe(false);
290
+ });
291
+
292
+ it("should not affect test type filters (flaky, retry)", () => {
293
+ treeFilter.value = { ...defaultFilter, flaky: true, retry: true };
294
+
295
+ setTransitionFilter("new", true);
296
+
297
+ expect(treeFilter.value.flaky).toBe(true);
298
+ expect(treeFilter.value.retry).toBe(true);
299
+ expect(treeFilter.value.new).toBe(true);
300
+ });
301
+ });
302
+ });
@@ -139,6 +139,151 @@ describe("utils > treeFilters", () => {
139
139
  expect(result).toEqual([expect.objectContaining({ name: "a1" })]);
140
140
  });
141
141
 
142
+ it("filters leaves by name query", () => {
143
+ const leaves = ["a1", "b2", "c3"];
144
+ const leavesById = {
145
+ a1: {
146
+ name: "Login test",
147
+ nodeId: "id-001",
148
+ },
149
+ b2: {
150
+ name: "Logout test",
151
+ nodeId: "id-002",
152
+ },
153
+ c3: {
154
+ name: "Registration test",
155
+ nodeId: "id-003",
156
+ },
157
+ };
158
+ const result = filterLeaves(leaves, leavesById as any, {
159
+ query: "Login",
160
+ });
161
+
162
+ expect(result).toEqual([expect.objectContaining({ name: "Login test" })]);
163
+ });
164
+
165
+ it("filters leaves by nodeId query", () => {
166
+ const leaves = ["a1", "b2", "c3"];
167
+ const leavesById = {
168
+ a1: {
169
+ name: "Login test",
170
+ nodeId: "abc-123",
171
+ },
172
+ b2: {
173
+ name: "Logout test",
174
+ nodeId: "def-456",
175
+ },
176
+ c3: {
177
+ name: "Registration test",
178
+ nodeId: "ghi-789",
179
+ },
180
+ };
181
+ const result = filterLeaves(leaves, leavesById as any, {
182
+ query: "def-456",
183
+ });
184
+
185
+ expect(result).toEqual([expect.objectContaining({ name: "Logout test", nodeId: "def-456" })]);
186
+ });
187
+
188
+ it("does not match partial nodeId (exact match only)", () => {
189
+ const leaves = ["a1", "b2", "c3"];
190
+ const leavesById = {
191
+ a1: {
192
+ name: "Test 1",
193
+ nodeId: "feature-login-001",
194
+ },
195
+ b2: {
196
+ name: "Test 2",
197
+ nodeId: "feature-login-002",
198
+ },
199
+ c3: {
200
+ name: "Test 3",
201
+ nodeId: "feature-logout-001",
202
+ },
203
+ };
204
+ const result = filterLeaves(leaves, leavesById as any, {
205
+ query: "login",
206
+ });
207
+
208
+ // nodeId requires exact match, so no results by nodeId
209
+ expect(result).toEqual([]);
210
+ });
211
+
212
+ it("matches nodeId with exact query", () => {
213
+ const leaves = ["a1", "b2", "c3"];
214
+ const leavesById = {
215
+ a1: {
216
+ name: "Test 1",
217
+ nodeId: "feature-login-001",
218
+ },
219
+ b2: {
220
+ name: "Test 2",
221
+ nodeId: "feature-login-002",
222
+ },
223
+ c3: {
224
+ name: "Test 3",
225
+ nodeId: "feature-logout-001",
226
+ },
227
+ };
228
+ const result = filterLeaves(leaves, leavesById as any, {
229
+ query: "feature-login-001",
230
+ });
231
+
232
+ expect(result).toEqual([expect.objectContaining({ nodeId: "feature-login-001" })]);
233
+ });
234
+
235
+ it("filters leaves matching by name (partial) or nodeId (exact)", () => {
236
+ const leaves = ["a1", "b2", "c3"];
237
+ const leavesById = {
238
+ a1: {
239
+ name: "Search functionality",
240
+ nodeId: "test-001",
241
+ },
242
+ b2: {
243
+ name: "Login test",
244
+ nodeId: "search",
245
+ },
246
+ c3: {
247
+ name: "Logout test",
248
+ nodeId: "test-003",
249
+ },
250
+ };
251
+ const result = filterLeaves(leaves, leavesById as any, {
252
+ query: "search",
253
+ });
254
+
255
+ // Both results match: one by name (partial), one by nodeId (exact)
256
+ expect(result).toHaveLength(2);
257
+ expect(result).toEqual(
258
+ expect.arrayContaining([
259
+ expect.objectContaining({ name: "Search functionality" }),
260
+ expect.objectContaining({ nodeId: "search" }),
261
+ ]),
262
+ );
263
+ });
264
+
265
+ it("filters leaves case-insensitively by name (partial) and nodeId (exact)", () => {
266
+ const leaves = ["a1", "b2"];
267
+ const leavesById = {
268
+ a1: {
269
+ name: "LOGIN Test",
270
+ nodeId: "id-001",
271
+ },
272
+ b2: {
273
+ name: "Other test",
274
+ nodeId: "login",
275
+ },
276
+ };
277
+ const result = filterLeaves(leaves, leavesById as any, {
278
+ query: "login",
279
+ });
280
+
281
+ expect(result).toEqual([
282
+ expect.objectContaining({ name: "LOGIN Test" }),
283
+ expect.objectContaining({ nodeId: "login" }),
284
+ ]);
285
+ });
286
+
142
287
  it("sorts leave by duration in ascending order", () => {
143
288
  const leaves = ["a1", "b2", "c3"];
144
289
  const leavesById = {
package/types.d.ts CHANGED
@@ -77,6 +77,7 @@ export type AwesomeTestResult = Omit<
77
77
  retry: boolean;
78
78
  categories?: AwesomeCategory[];
79
79
  environment?: string | "default";
80
+ tooltips?: Record<string, string>;
80
81
  };
81
82
 
82
83
  export type AwesomeTreeLeaf = Pick<
@@ -85,6 +86,7 @@ export type AwesomeTreeLeaf = Pick<
85
86
  > & {
86
87
  nodeId: string;
87
88
  transitionTooltip?: string;
89
+ tooltips?: Record<string, string>;
88
90
  };
89
91
 
90
92
  export type AwesomeTreeGroup = WithChildren & DefaultTreeGroup & { nodeId: string };
@@ -1 +0,0 @@
1
- "use strict";(self.webpackChunk_allurereport_web_awesome=self.webpackChunk_allurereport_web_awesome||[]).push([[174],{4174:function(t){t.exports=JSON.parse('{"statuses":{"passed":"passed","failed":"failed","broken":"broken","skipped":"skipped","unknown":"unknown","total":"total","flakyTests":"flaky","newTests":"new","retryTests":"retry"},"testSummary":{"total":"Total","flaky":"Flaky tests","retries":"Retried tests","new":"New tests"},"tabs":{"total":"All","results":"Results","globalAttachments":"Global Attachments","globalErrors":"Global Errors","qualityGates":"Quality Gates"},"search":{"search":"Search","search-placeholder":"Name or ID"},"filters":{"more-filters":"More filters","enable-filter":"Enable \\"{{filter}}\\" filter","flaky":"Flaky","retry":"Retry","new":"New","fixed":"Fixed","regressed":"Regressed","malfunctioned":"Malfuctioned"},"filters.description":{"flaky":"Show unstable tests","retry":"Show test results that were rerun","new":"Show test results that appear for the first time in this report","fixed":"Show tests that are passed now but had been \\"failed\\" or \\"broken\\" in a previous report","regressed":"Show test results that changed to \\"failed\\" status from \\"passed\\" or \\"broken\\" status","malfunctioned":"Show test results that changed to \\"broken\\" status from \\"passed\\" or \\"failed\\" status"},"sort-by":{"sort-by-text":"Sort by:","sort-by-category":"Sort by","direction-category":"Direction"},"sort-by.values":{"order":"Order","alphabet":"Alphabet","duration":"Duration","status":"Status"},"sort-by.directions":{"order-desc":"Latest – Earliest","order-asc":"Earliest – Latest","order-asc-short":"Earliest","order-desc-short":"Latest","alphabet-asc":"A – Z","alphabet-desc":"Z – A","alphabet-asc-short":"A – Z","alphabet-desc-short":"Z – A","duration-asc":"1 – 9","duration-desc":"9 – 1","duration-asc-short":"1 – 9","duration-desc-short":"9 – 1","status-asc":"As in the filter list","status-desc":"Reversed","status-asc-short":"Regular","status-desc-short":"Reversed"},"empty":{"no-results":"No results","no-tests-found":"No results found","no-message-provided":"No message is provided","clear-filters":"Clear filters","no-attachments-results":"No attachments information available","no-global-errors-results":"No global errors information available","no-quality-gate-results":"No quality gate results available","no-history-results":"No history information available","no-retries-results":"No retries information available","no-test-steps-results":"No test steps information available","no-test-case-results":"No test case results","no-environments-results":"No environments information available"},"severity":{"blocker":"blocker","critical":"critical","normal":"normal","minor":"minor","trivial":"trivial"},"execution":{"name":"Execution","body":"Test body","setup":"Set up","teardown":"Tear down"},"environments":{"environment_one":"Environment","environment_other":"Environments","all":"All"},"ui":{"labels":"Labels","metadata":"Metadata","parameters":"Parameters","description":"Description","links":"Links","overview":"Overview","history":"History","attachments":"Attachments","retries":"Retries","environments":"Environments","error":"Error","goToStep":"Go to step","showLess":"Show less","showMore":"Show more","copy":"Copy","attempt":"Attempt {{attempt}} of {{total}}","at":"at","variables":"Variables","openPwTrace":"Open Playwright Trace","finishedAtOriginal":"{{formattedCreatedAt}}, with exit code {{original}}","finishedAtBoth":"{{formattedCreatedAt}}, with exit code {{actual}} (original {{original}})"},"controls":{"newTabAttachment":"Open attachment in new tab","nextTR":"Next Test result","prevTR":"Previous Test result","downloadAttachment":"Download attachment","backto":"Back to","clipboard":"Copy to clipboard","clipboardError":"Can not copy value to clipboard. Seems like this feature is not supported for your browser","clipboardSuccess":"Successfully copied","collapse":"Collapse","expand":"Expand","fullscreen":"Full screen","language":"Change language","openInNewTab":"Open in new tab","openPreview":"Open preview","noSelectedTR":"No selected Test result","comparison":"Comparison","showDiff":"Show difference","viewMode":"View mode","unified":"Unified","side-by-side":"Side by Side","compareBy":"Compare by","chars":"chars","words":"words","lines":"lines","actual":"Actual","expected":"Expected"},"errors":{"missedAttachment":"Attachment not found"},"sections":{"report":"Report","charts":"Graphs","timeline":"Timeline"},"timeline":{"empty":"No data","empty_host":"No data for {{ host }}","selected_one":"Selected {{ count }} test ({{ percentage }}%) with duration more than {{ minDuration }} and less than {{ maxDuration }}","selected_other":"Selected {{ count }} tests ({{ percentage }}%) with duration more than {{ minDuration }} and less than {{ maxDuration }}","host":"Host: {{ host }}"},"charts":{"trend":{"title":"Trend Chart: {{type}}","type":{"status":"Status","severity":"Severity"}},"currentStatus":{"title":"Current Status","status":{"passed":"$t(statuses:passed, capitalize)","failed":"$t(statuses:failed, capitalize)","broken":"$t(statuses:broken, capitalize)","skipped":"$t(statuses:skipped, capitalize)","unknown":"$t(statuses:unknown, capitalize)"},"percentage":"{{percentage}}%","of":"of {{total}}","total":"total","tests":{"new_zero":"No new tests","new_one":"{{count}} new test","new_other":"{{count}} new tests","flaky_zero":"No flaky tests","flaky_one":"{{count}} flaky test","flaky_other":"{{count}} flaky tests","retries_zero":"No retried tests","retries_one":"{{count}} retried test","retries_other":"{{count}} retried tests"}},"statusDynamics":{"title":"Status dynamics","status":{"passed":"$t(statuses:passed, capitalize)","failed":"$t(statuses:failed, capitalize)","broken":"$t(statuses:broken, capitalize)","skipped":"$t(statuses:skipped, capitalize)","unknown":"$t(statuses:unknown, capitalize)"},"no-history":"$t(empty:no-history-results)","no-results":"$t(empty:no-results)","tooltips":{"current":"Latest report ({{timestamp, timestamp_long_no_seconds}})","history":"Report from {{timestamp, timestamp_long_no_seconds}}"},"ticks":{"current":"Latest","history":"{{timestamp, timestamp_date}}"}},"statusTransitions":{"title":"Status transitions","legend":{"trend":"Fix rate"},"transitions":{"new":"$t(transitions:new, capitalize)","fixed":"$t(transitions:fixed, capitalize)","regressed":"$t(transitions:regressed, capitalize)","malfunctioned":"$t(transitions:malfunctioned, capitalize)"},"no-history":"$t(empty:no-history-results)","no-results":"$t(empty:no-results)","tooltips":{"current":"Latest report ({{timestamp, timestamp_long_no_seconds}})","history":"Report from {{timestamp, timestamp_long_no_seconds}}"},"ticks":{"current":"Latest","history":"{{timestamp, timestamp_date}}"}},"durations":{"title":"Durations by {{groupBy}} histogram","title_none":"Durations histogram","no-results":"$t(empty:no-results)","groupBy":{"none":"None","layer":"Layer"},"ticks":{"durationRange":"{{from, format_duration}} - {{to, format_duration}}"},"tooltips":{"durationRange":"{{from, format_duration}} - {{to, format_duration}}"},"legend":{"value":"{{value}}","total":"Tests count"}},"stabilityDistribution":{"title":"Stability distribution","no-results":"$t(empty:no-results)","legend":{"stabilityRate":"Stability rate"}},"testBaseGrowthDynamics":{"title":"Test base growth dynamics","status":{"newpassed":"New $t(statuses:passed)","newfailed":"New $t(statuses:failed)","newbroken":"New $t(statuses:broken)","newskipped":"New $t(statuses:skipped)","newunknown":"New $t(statuses:unknown)","removedpassed":"Removed $t(statuses:passed)","removedfailed":"Removed $t(statuses:failed)","removedbroken":"Removed $t(statuses:broken)","removedskipped":"Removed $t(statuses:skipped)","removedunknown":"Removed $t(statuses:unknown)"},"legend":{"trend":"Growth trend"},"no-history":"$t(empty:no-history-results)","no-results":"$t(empty:no-results)","tooltips":{"current":"Latest report ({{timestamp, timestamp_long_no_seconds}})","history":"Report from {{timestamp, timestamp_long_no_seconds}}"},"ticks":{"current":"Latest","history":"{{timestamp, timestamp_date}}"}},"fbsuAgePyramid":{"title":"FBSU age pyramid","status":{"passed":"$t(statuses:passed, capitalize)","failed":"$t(statuses:failed, capitalize)","broken":"$t(statuses:broken, capitalize)","skipped":"$t(statuses:skipped, capitalize)","unknown":"$t(statuses:unknown, capitalize)"},"no-history":"$t(empty:no-history-results)","no-results":"$t(empty:no-results)","tooltips":{"current":"Latest report ({{timestamp, timestamp_long_no_seconds}})","history":"Report from {{timestamp, timestamp_long_no_seconds}}"},"ticks":{"current":"Latest","history":"{{timestamp, timestamp_date}}"}},"trSeverities":{"title":"Test results by severities","no-results":"$t(empty:no-results)","status":{"passed":"$t(statuses:passed, capitalize)","failed":"$t(statuses:failed, capitalize)","broken":"$t(statuses:broken, capitalize)","skipped":"$t(statuses:skipped, capitalize)","unknown":"$t(statuses:unknown, capitalize)"},"severity":{"blocker":"$t(severity:blocker, capitalize)","critical":"$t(severity:critical, capitalize)","normal":"$t(severity:normal, capitalize)","minor":"$t(severity:minor, capitalize)","trivial":"$t(severity:trivial, capitalize)","unset":"No severity"}},"durationDynamics":{"title":"Duration dynamics","durations":{"sequential":"Sequential duration","duration":"Test duration","speedup":"Speedup"},"no-results":"$t(empty:no-results)","tooltips":{"current":"Latest report ({{timestamp, timestamp_long_no_seconds}})","history":"Report from {{timestamp, timestamp_long_no_seconds}}"},"ticks":{"current":"Latest","history":"{{timestamp, timestamp_date}}"},"legend":{"duration":"{{duration, format_duration}}","speedup":"{{speedup}}x"}}},"transitions":{"description":{"new":"The first occurrence of this test result in the report","fixed":"A previously \\"failed\\" or \\"broken\\" test that is now \\"passed\\"","regressed":"A previously \\"passed\\" or \\"broken\\" test that is now \\"failed\\"","malfunctioned":"A previously \\"passed\\" or \\"failed\\" test that is now \\"broken\\""},"new":"new","fixed":"fixed","regressed":"regressed","malfunctioned":"malfunctioned"}}')}}]);