@allurereport/web-awesome 3.8.1 → 3.9.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.
Files changed (207) hide show
  1. package/README.md +112 -0
  2. package/allurerc-dev.mjs +10 -0
  3. package/dist/multi/121.app-d36b0855e3e7a53eeee9.js +1 -0
  4. package/dist/multi/173.app-d36b0855e3e7a53eeee9.js +1 -0
  5. package/dist/multi/174.app-d36b0855e3e7a53eeee9.js +1 -0
  6. package/dist/multi/252.app-d36b0855e3e7a53eeee9.js +1 -0
  7. package/dist/multi/282.app-d36b0855e3e7a53eeee9.js +1 -0
  8. package/dist/multi/29.app-d36b0855e3e7a53eeee9.js +1 -0
  9. package/dist/multi/310.app-d36b0855e3e7a53eeee9.js +1 -0
  10. package/dist/multi/{416.app-200938be3feda27d7b80.js → 416.app-d36b0855e3e7a53eeee9.js} +1 -1
  11. package/dist/multi/{507.app-200938be3feda27d7b80.js → 507.app-d36b0855e3e7a53eeee9.js} +1 -1
  12. package/dist/multi/527.app-d36b0855e3e7a53eeee9.js +1 -0
  13. package/dist/multi/600.app-d36b0855e3e7a53eeee9.js +1 -0
  14. package/dist/multi/605.app-d36b0855e3e7a53eeee9.js +1 -0
  15. package/dist/multi/638.app-d36b0855e3e7a53eeee9.js +1 -0
  16. package/dist/multi/672.app-d36b0855e3e7a53eeee9.js +1 -0
  17. package/dist/multi/686.app-d36b0855e3e7a53eeee9.js +1 -0
  18. package/dist/multi/725.app-d36b0855e3e7a53eeee9.js +1 -0
  19. package/dist/multi/741.app-d36b0855e3e7a53eeee9.js +1 -0
  20. package/dist/multi/749.app-d36b0855e3e7a53eeee9.js +1 -0
  21. package/dist/multi/755.app-d36b0855e3e7a53eeee9.js +1 -0
  22. package/dist/multi/779.app-d36b0855e3e7a53eeee9.js +1 -0
  23. package/dist/multi/{894.app-200938be3feda27d7b80.js → 894.app-d36b0855e3e7a53eeee9.js} +1 -1
  24. package/dist/multi/943.app-d36b0855e3e7a53eeee9.js +1 -0
  25. package/dist/multi/980.app-d36b0855e3e7a53eeee9.js +1 -0
  26. package/dist/multi/app-d36b0855e3e7a53eeee9.js +2 -0
  27. package/dist/multi/manifest.json +26 -23
  28. package/dist/multi/styles-212da6c68fa0beb4c6c5.css +1 -0
  29. package/dist/multi/styles-468416ffee9a9dea6cae.css +58 -0
  30. package/dist/multi/styles-5c882b14b6f3112e40c4.css +1 -0
  31. package/dist/single/app-62171f5f51b5954a787c.js +2 -0
  32. package/dist/single/manifest.json +1 -1
  33. package/package.json +13 -8
  34. package/src/assets/scss/_common.scss +2 -2
  35. package/src/assets/scss/index.scss +8 -6
  36. package/src/components/BaseLayout/index.tsx +14 -2
  37. package/src/components/BaseLayout/styles.scss +5 -5
  38. package/src/components/Categories/CategoryHeaderItem/styles.scss +2 -2
  39. package/src/components/Categories/CategoryTreeItem/styles.scss +2 -2
  40. package/src/components/Categories/GroupTreeItem/styles.scss +4 -5
  41. package/src/components/Categories/HistoryTreeItem/styles.scss +2 -2
  42. package/src/components/Categories/LabelTreeItem/styles.scss +2 -2
  43. package/src/components/Categories/MessageTreeItem/index.tsx +1 -1
  44. package/src/components/Categories/MessageTreeItem/styles.scss +18 -18
  45. package/src/components/Categories/sticky.ts +1 -1
  46. package/src/components/Footer/styles.scss +2 -2
  47. package/src/components/Header/CiInfo/styles.scss +1 -1
  48. package/src/components/Header/styles.scss +2 -2
  49. package/src/components/HotkeysProvider/index.tsx +556 -0
  50. package/src/components/KeyboardShortcuts/index.tsx +73 -0
  51. package/src/components/KeyboardShortcuts/shortcutsConfig.ts +91 -0
  52. package/src/components/KeyboardShortcuts/styles.scss +69 -0
  53. package/src/components/MainReport/index.tsx +89 -72
  54. package/src/components/MainReport/styles.scss +40 -4
  55. package/src/components/Metadata/styles.scss +9 -9
  56. package/src/components/MetadataButton/index.tsx +2 -0
  57. package/src/components/MetadataButton/styles.scss +1 -1
  58. package/src/components/NavTabs/styles.scss +8 -8
  59. package/src/components/ReportBody/index.tsx +11 -2
  60. package/src/components/ReportBody/styles.scss +24 -4
  61. package/src/components/ReportCategories/styles.scss +1 -1
  62. package/src/components/ReportFilters/styles.scss +1 -1
  63. package/src/components/ReportGlobalAttachments/styles.scss +1 -1
  64. package/src/components/ReportGlobalErrors/styles.scss +1 -1
  65. package/src/components/ReportHeader/styles.scss +2 -2
  66. package/src/components/ReportMetadata/index.tsx +9 -11
  67. package/src/components/ReportMetadata/styles.scss +6 -6
  68. package/src/components/ReportQualityGateResults/styles.scss +2 -2
  69. package/src/components/ReportSearch/index.tsx +1 -5
  70. package/src/components/ReportTabs/styles.scss +9 -9
  71. package/src/components/SectionSwitcher/index.tsx +87 -10
  72. package/src/components/SideBySide/index.tsx +20 -2
  73. package/src/components/SideBySide/styles.scss +9 -1
  74. package/src/components/SplitLayout/index.tsx +10 -1
  75. package/src/components/SplitLayout/styles.scss +20 -4
  76. package/src/components/TestResult/TestStepsEmpty/styles.scss +1 -1
  77. package/src/components/TestResult/TrDescription/styles.scss +1 -1
  78. package/src/components/TestResult/TrDropdown/index.tsx +2 -2
  79. package/src/components/TestResult/TrDropdown/styles.scss +1 -1
  80. package/src/components/TestResult/TrEmpty/styles.scss +1 -1
  81. package/src/components/TestResult/TrEnvironmentItem/styles.scss +4 -4
  82. package/src/components/TestResult/TrError/index.tsx +32 -7
  83. package/src/components/TestResult/TrError/styles.scss +23 -23
  84. package/src/components/TestResult/TrHeader/styles.scss +2 -2
  85. package/src/components/TestResult/TrHistory/styles.scss +6 -6
  86. package/src/components/TestResult/TrInfo/styles.scss +8 -8
  87. package/src/components/TestResult/TrLinks/index.tsx +2 -2
  88. package/src/components/TestResult/TrLinks/styles.scss +2 -2
  89. package/src/components/TestResult/TrMetadata/index.tsx +1 -1
  90. package/src/components/TestResult/TrMetadata/styles.scss +1 -1
  91. package/src/components/TestResult/TrNavigation/index.tsx +1 -1
  92. package/src/components/TestResult/TrNavigation/styles.scss +2 -2
  93. package/src/components/TestResult/TrOverview.tsx +2 -0
  94. package/src/components/TestResult/TrParameters/index.tsx +1 -1
  95. package/src/components/TestResult/TrParameters/styles.scss +1 -1
  96. package/src/components/TestResult/TrPrevStatuses/styles.scss +8 -8
  97. package/src/components/TestResult/TrPwTraces/openPwTraceInNewTab.ts +2 -2
  98. package/src/components/TestResult/TrPwTraces/styles.scss +1 -1
  99. package/src/components/TestResult/TrRetriesView/styles.scss +3 -3
  100. package/src/components/TestResult/TrSetup/index.tsx +9 -3
  101. package/src/components/TestResult/TrSeverity/styles.scss +7 -7
  102. package/src/components/TestResult/TrStatus/styles.scss +2 -35
  103. package/src/components/TestResult/TrSteps/TrAttachment.tsx +79 -43
  104. package/src/components/TestResult/TrSteps/TrAttachmentInfo.tsx +44 -17
  105. package/src/components/TestResult/TrSteps/TrErrorStep.tsx +3 -0
  106. package/src/components/TestResult/TrSteps/TrStep.tsx +9 -4
  107. package/src/components/TestResult/TrSteps/TrStepHeader.tsx +8 -5
  108. package/src/components/TestResult/TrSteps/index.tsx +7 -4
  109. package/src/components/TestResult/TrSteps/stepTreeExpansion.ts +27 -9
  110. package/src/components/TestResult/TrSteps/styles.scss +80 -20
  111. package/src/components/TestResult/TrTeardown/index.tsx +9 -3
  112. package/src/components/TestResult/bodyItems.ts +1 -1
  113. package/src/components/TestResult/index.tsx +8 -2
  114. package/src/components/TestResult/styles.scss +10 -1
  115. package/src/components/TestResult/trOverviewFocus.scss +4 -0
  116. package/src/components/Timeline/styles.scss +6 -6
  117. package/src/components/Tree/index.tsx +54 -5
  118. package/src/components/Tree/styles.scss +55 -35
  119. package/src/hooks/useTestResultOverviewFocusScroll.ts +23 -0
  120. package/src/index.html +30 -33
  121. package/src/index.tsx +12 -6
  122. package/src/locales/ar.json +61 -1
  123. package/src/locales/az.json +61 -1
  124. package/src/locales/de.json +61 -1
  125. package/src/locales/en.json +61 -1
  126. package/src/locales/es.json +61 -1
  127. package/src/locales/fr.json +61 -1
  128. package/src/locales/he.json +61 -1
  129. package/src/locales/hy.json +61 -1
  130. package/src/locales/it.json +61 -1
  131. package/src/locales/ja.json +61 -1
  132. package/src/locales/ka.json +61 -1
  133. package/src/locales/kr.json +61 -1
  134. package/src/locales/nl.json +61 -1
  135. package/src/locales/pl.json +61 -1
  136. package/src/locales/pt.json +61 -1
  137. package/src/locales/ru.json +61 -1
  138. package/src/locales/sv.json +61 -1
  139. package/src/locales/tr.json +61 -1
  140. package/src/locales/uk.json +61 -1
  141. package/src/locales/zh-TW.json +61 -1
  142. package/src/locales/zh.json +61 -1
  143. package/src/stores/keyboard.ts +371 -0
  144. package/src/stores/keyboardActions.ts +769 -0
  145. package/src/stores/locale.ts +1 -0
  146. package/src/stores/reportEnvSections.ts +6 -0
  147. package/src/stores/reportRootTabs.ts +95 -0
  148. package/src/stores/search.ts +147 -0
  149. package/src/stores/testResultOverviewNav.ts +119 -0
  150. package/src/stores/testResultTabs.ts +62 -0
  151. package/src/stores/timeline.ts +1 -1
  152. package/src/stores/tree.ts +42 -4
  153. package/src/stores/treeFilters/store.ts +3 -36
  154. package/src/styles/_pane-active.scss +8 -0
  155. package/src/styles.scss +1 -1
  156. package/src/utils/flattenTestResultOverview.ts +182 -0
  157. package/src/utils/trOverviewFocus.ts +18 -0
  158. package/test/components/EnvironmentPicker.test.tsx +21 -3
  159. package/test/components/Header/CiInfo.test.tsx +8 -0
  160. package/test/components/Header.test.tsx +8 -0
  161. package/test/components/ReportGlobals.test.tsx +9 -1
  162. package/test/components/TestResult/PwTraceButton.test.tsx +8 -0
  163. package/test/components/TestResult/TrErrorStep.test.tsx +8 -0
  164. package/test/components/TestResult/TrOverview.test.tsx +30 -10
  165. package/test/components/TestResult/TrSteps.test.tsx +73 -0
  166. package/test/components/TestResult/bodyItems.test.ts +9 -1
  167. package/test/components/TestResult/openPwTraceInNewTab.test.ts +8 -0
  168. package/test/components/TestResult/stepTreeExpansion.test.ts +10 -2
  169. package/test/components/Timeline.test.tsx +15 -7
  170. package/test/stores/keyboard/keyboardActions.test.ts +615 -0
  171. package/test/stores/search.test.ts +143 -0
  172. package/test/stores/treeFilters/actions.test.ts +8 -0
  173. package/test/utils/flattenTestResultOverview.test.ts +57 -0
  174. package/test/utils/ownerAddress.test.ts +9 -1
  175. package/test/utils/treeFilters.test.ts +9 -1
  176. package/types.d.ts +17 -0
  177. package/webpack.config.js +3 -0
  178. package/CONTRIBUTING.md +0 -34
  179. package/dist/multi/173.app-200938be3feda27d7b80.js +0 -1
  180. package/dist/multi/174.app-200938be3feda27d7b80.js +0 -1
  181. package/dist/multi/252.app-200938be3feda27d7b80.js +0 -1
  182. package/dist/multi/282.app-200938be3feda27d7b80.js +0 -1
  183. package/dist/multi/29.app-200938be3feda27d7b80.js +0 -1
  184. package/dist/multi/310.app-200938be3feda27d7b80.js +0 -1
  185. package/dist/multi/527.app-200938be3feda27d7b80.js +0 -1
  186. package/dist/multi/600.app-200938be3feda27d7b80.js +0 -1
  187. package/dist/multi/605.app-200938be3feda27d7b80.js +0 -1
  188. package/dist/multi/638.app-200938be3feda27d7b80.js +0 -1
  189. package/dist/multi/672.app-200938be3feda27d7b80.js +0 -1
  190. package/dist/multi/686.app-200938be3feda27d7b80.js +0 -1
  191. package/dist/multi/725.app-200938be3feda27d7b80.js +0 -1
  192. package/dist/multi/741.app-200938be3feda27d7b80.js +0 -1
  193. package/dist/multi/749.app-200938be3feda27d7b80.js +0 -1
  194. package/dist/multi/755.app-200938be3feda27d7b80.js +0 -1
  195. package/dist/multi/943.app-200938be3feda27d7b80.js +0 -1
  196. package/dist/multi/980.app-200938be3feda27d7b80.js +0 -1
  197. package/dist/multi/app-200938be3feda27d7b80.js +0 -2
  198. package/dist/multi/styles-9f7a23a0c8b79fa76981.css +0 -58
  199. package/dist/single/app-17629d1b119f6c611d49.js +0 -2
  200. package/src/assets/scss/day.scss +0 -53
  201. package/src/assets/scss/fonts.scss +0 -3
  202. package/src/assets/scss/night.scss +0 -63
  203. package/src/assets/scss/palette.scss +0 -393
  204. package/src/assets/scss/theme.scss +0 -330
  205. package/src/assets/scss/vars.scss +0 -11
  206. /package/dist/multi/{app-200938be3feda27d7b80.js.LICENSE.txt → app-d36b0855e3e7a53eeee9.js.LICENSE.txt} +0 -0
  207. /package/dist/single/{app-17629d1b119f6c611d49.js.LICENSE.txt → app-62171f5f51b5954a787c.js.LICENSE.txt} +0 -0
@@ -0,0 +1,182 @@
1
+ import type { FlatTreeNode } from "@allurereport/web-commons";
2
+
3
+ import type { TrBodyItem } from "@/components/TestResult/bodyItems";
4
+ import { hasTestLevelErrorContent } from "@/components/TestResult/bodyItems";
5
+ import {
6
+ getStepTreeExpansionPolicy,
7
+ hasStepContent,
8
+ isStepOpenedByDefault,
9
+ type StepTreeExpansion,
10
+ } from "@/components/TestResult/TrSteps/stepTreeExpansion";
11
+
12
+ export type FlattenTestResultOverviewInput = {
13
+ testResultId: string;
14
+ hasSetup: boolean;
15
+ setupBodyItems: TrBodyItem[];
16
+ bodyItems: TrBodyItem[];
17
+ hasTeardown: boolean;
18
+ teardownBodyItems: TrBodyItem[];
19
+ isGroupOpened: (id: string, openedByDefault: boolean) => boolean;
20
+ stepExpansionPolicy?: StepTreeExpansion;
21
+ };
22
+
23
+ const sectionId = (testResultId: string, section: string) => `${testResultId}-${section}`;
24
+
25
+ const pushSection = (
26
+ result: FlatTreeNode[],
27
+ options: {
28
+ id: string;
29
+ depth: number;
30
+ parentId?: string;
31
+ openedByDefault?: boolean;
32
+ isGroupOpened: FlattenTestResultOverviewInput["isGroupOpened"];
33
+ },
34
+ ) => {
35
+ const openedByDefault = options.openedByDefault ?? true;
36
+ const isExpanded = options.isGroupOpened(options.id, openedByDefault);
37
+
38
+ result.push({
39
+ kind: "group",
40
+ id: options.id,
41
+ nodeId: options.id,
42
+ depth: options.depth,
43
+ parentId: options.parentId,
44
+ hasChildren: true,
45
+ isExpanded,
46
+ openedByDefault,
47
+ });
48
+ };
49
+
50
+ const flattenBodyItems = (
51
+ bodyItems: TrBodyItem[],
52
+ depth: number,
53
+ parentId: string,
54
+ policy: StepTreeExpansion,
55
+ isGroupOpened: FlattenTestResultOverviewInput["isGroupOpened"],
56
+ ): FlatTreeNode[] => {
57
+ const result: FlatTreeNode[] = [];
58
+
59
+ for (const bodyItem of bodyItems) {
60
+ if (bodyItem.type === "step") {
61
+ const stepId = bodyItem.item.stepId;
62
+ const openedByDefault = isStepOpenedByDefault(policy, bodyItem.item.status, bodyItem.bodyItems);
63
+ const hasContent = hasStepContent(bodyItem);
64
+ const isExpanded = isGroupOpened(stepId, openedByDefault);
65
+
66
+ result.push({
67
+ kind: hasContent ? "group" : "leaf",
68
+ id: stepId,
69
+ nodeId: stepId,
70
+ depth,
71
+ parentId,
72
+ hasChildren: hasContent,
73
+ isExpanded: hasContent ? isExpanded : undefined,
74
+ openedByDefault,
75
+ });
76
+
77
+ if (hasContent && isExpanded) {
78
+ result.push(...flattenBodyItems(bodyItem.bodyItems, depth + 1, stepId, policy, isGroupOpened));
79
+ }
80
+
81
+ continue;
82
+ }
83
+
84
+ if (bodyItem.type === "error" && hasTestLevelErrorContent(bodyItem.error)) {
85
+ const openedByDefault = policy !== "collapsed";
86
+ const isExpanded = isGroupOpened(bodyItem.id, openedByDefault);
87
+
88
+ result.push({
89
+ kind: "group",
90
+ id: bodyItem.id,
91
+ nodeId: bodyItem.id,
92
+ depth,
93
+ parentId,
94
+ hasChildren: true,
95
+ isExpanded,
96
+ openedByDefault,
97
+ });
98
+ continue;
99
+ }
100
+
101
+ if (bodyItem.type === "attachment") {
102
+ const attachmentTreeId = `attachment-${bodyItem.link.id}`;
103
+
104
+ result.push({
105
+ kind: "leaf",
106
+ id: bodyItem.link.id,
107
+ nodeId: attachmentTreeId,
108
+ depth,
109
+ parentId,
110
+ openedByDefault: false,
111
+ });
112
+ }
113
+ }
114
+
115
+ return result;
116
+ };
117
+
118
+ export const flattenTestResultOverview = (input: FlattenTestResultOverviewInput): FlatTreeNode[] => {
119
+ const { testResultId, hasSetup, setupBodyItems, bodyItems, hasTeardown, teardownBodyItems, isGroupOpened } = input;
120
+ const policy = input.stepExpansionPolicy ?? getStepTreeExpansionPolicy();
121
+ const result: FlatTreeNode[] = [];
122
+ let lastSectionId: string | undefined;
123
+
124
+ const appendSection = (section: string, openedByDefault = true) => {
125
+ const id = sectionId(testResultId, section);
126
+ pushSection(result, {
127
+ id,
128
+ depth: 0,
129
+ parentId: lastSectionId,
130
+ openedByDefault,
131
+ isGroupOpened,
132
+ });
133
+ lastSectionId = id;
134
+ return id;
135
+ };
136
+
137
+ if (hasSetup) {
138
+ const setupId = appendSection("setup");
139
+
140
+ if (isGroupOpened(setupId, true) && setupBodyItems.length > 0) {
141
+ const setupSteps = flattenBodyItems(setupBodyItems, 1, setupId, policy, isGroupOpened);
142
+ result.push(...setupSteps);
143
+
144
+ if (setupSteps.length > 0) {
145
+ lastSectionId = setupSteps[setupSteps.length - 1]!.id;
146
+ }
147
+ }
148
+ }
149
+
150
+ if (bodyItems.length > 0) {
151
+ const stepsId = sectionId(testResultId, "steps");
152
+ const stepsOpenedByDefault = policy !== "collapsed";
153
+ const stepsExpanded = isGroupOpened(stepsId, stepsOpenedByDefault);
154
+
155
+ pushSection(result, {
156
+ id: stepsId,
157
+ depth: 0,
158
+ parentId: lastSectionId,
159
+ openedByDefault: stepsOpenedByDefault,
160
+ isGroupOpened,
161
+ });
162
+ lastSectionId = stepsId;
163
+
164
+ if (stepsExpanded) {
165
+ const stepNodes = flattenBodyItems(bodyItems, 1, stepsId, policy, isGroupOpened);
166
+ result.push(...stepNodes);
167
+ if (stepNodes.length > 0) {
168
+ lastSectionId = stepNodes[stepNodes.length - 1]!.id;
169
+ }
170
+ }
171
+ }
172
+
173
+ if (hasTeardown) {
174
+ const teardownId = appendSection("teardown");
175
+
176
+ if (isGroupOpened(teardownId, true) && teardownBodyItems.length > 0) {
177
+ result.push(...flattenBodyItems(teardownBodyItems, 1, teardownId, policy, isGroupOpened));
178
+ }
179
+ }
180
+
181
+ return result;
182
+ };
@@ -0,0 +1,18 @@
1
+ import clsx from "clsx";
2
+
3
+ import { testResultFocusId } from "@/stores/testResultOverviewNav";
4
+
5
+ import * as styles from "@/components/TestResult/trOverviewFocus.scss";
6
+
7
+ export const isTrOverviewFocused = (id: string | null | undefined) => Boolean(id && testResultFocusId.value === id);
8
+
9
+ /** Focus ring for a section/step header row only (pass as `className` on the header control). */
10
+ export const trOverviewHeaderFocusClass = (id: string | null | undefined, className?: string) =>
11
+ clsx(className, isTrOverviewFocused(id) && styles["tr-overview-focused"]);
12
+
13
+ export const trOverviewFocusAttrs = (id: string | null | undefined) =>
14
+ id
15
+ ? {
16
+ "data-tr-focus-id": id,
17
+ }
18
+ : {};
@@ -1,6 +1,14 @@
1
- import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/preact";
1
+ import { act, cleanup, fireEvent, render, screen, waitFor } from "@testing-library/preact";
2
+ import { epic, feature, label, story } from "allure-js-commons";
2
3
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
4
 
5
+ beforeEach(async () => {
6
+ await epic("coverage");
7
+ await feature("ui-components");
8
+ await story("EnvironmentPicker");
9
+ await label("coverage", "ui-components");
10
+ });
11
+
4
12
  import { currentEnvironment, environmentsStore } from "@/stores/env";
5
13
 
6
14
  const longEnvironmentName = "я".repeat(64);
@@ -65,6 +73,7 @@ describe("components > EnvironmentPicker", () => {
65
73
  let restoreElementSizeMocks: () => void;
66
74
 
67
75
  beforeEach(() => {
76
+ vi.useFakeTimers();
68
77
  vi.stubGlobal(
69
78
  "matchMedia",
70
79
  vi.fn().mockImplementation(() => ({
@@ -96,6 +105,8 @@ describe("components > EnvironmentPicker", () => {
96
105
  restoreElementSizeMocks();
97
106
  vi.unstubAllGlobals();
98
107
  cleanup();
108
+ vi.runOnlyPendingTimers();
109
+ vi.useRealTimers();
99
110
  });
100
111
 
101
112
  it("should show tooltip on hover after resize truncates selected value", async () => {
@@ -108,14 +119,21 @@ describe("components > EnvironmentPicker", () => {
108
119
 
109
120
  expect(queryTooltip()).not.toBeInTheDocument();
110
121
 
111
- setNarrowViewport(true);
112
- await waitFor(() => {
122
+ await act(async () => {
123
+ setNarrowViewport(true);
113
124
  fireEvent(window, new Event("resize"));
125
+ vi.advanceTimersByTime(16);
126
+ });
127
+
128
+ await waitFor(() => {
114
129
  expect(getTooltipTrigger().childElementCount).toBe(2);
115
130
  });
116
131
 
117
132
  const tooltipTrigger = getTooltipTrigger();
118
133
  fireEvent.mouseEnter(tooltipTrigger);
134
+ await act(async () => {
135
+ vi.advanceTimersByTime(200);
136
+ });
119
137
  await waitFor(() => {
120
138
  expect(queryTooltip()).toBeInTheDocument();
121
139
  });
@@ -1,9 +1,17 @@
1
1
  import { CiType } from "@allurereport/core-api";
2
2
  import { getReportOptions } from "@allurereport/web-commons";
3
3
  import { cleanup, render, screen } from "@testing-library/preact";
4
+ import { epic, feature, label, story } from "allure-js-commons";
4
5
  import { h } from "preact";
5
6
  import { type Mock, beforeEach, describe, expect, it, vi } from "vitest";
6
7
 
8
+ beforeEach(async () => {
9
+ await epic("coverage");
10
+ await feature("ui-components");
11
+ await story("CiInfo");
12
+ await label("coverage", "ui-components");
13
+ });
14
+
7
15
  import { CiInfo } from "@/components/Header/CiInfo";
8
16
 
9
17
  const fixtures = {
@@ -1,8 +1,16 @@
1
1
  import * as webCommons from "@allurereport/web-commons";
2
2
  import { signal } from "@preact/signals";
3
3
  import { cleanup, render, screen } from "@testing-library/preact";
4
+ import { epic, feature, label, story } from "allure-js-commons";
4
5
  import { beforeEach, describe, expect, it, vi } from "vitest";
5
6
 
7
+ beforeEach(async () => {
8
+ await epic("coverage");
9
+ await feature("ui-components");
10
+ await story("Header");
11
+ await label("coverage", "ui-components");
12
+ });
13
+
6
14
  import { Header } from "@/components/Header";
7
15
  import { CiInfo } from "@/components/Header/CiInfo";
8
16
  import type * as routerModule from "@/stores/router";
@@ -1,6 +1,14 @@
1
1
  import { signal } from "@preact/signals";
2
2
  import { cleanup, render, screen } from "@testing-library/preact";
3
- import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import { epic, feature, label, story } from "allure-js-commons";
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
+
6
+ beforeEach(async () => {
7
+ await epic("coverage");
8
+ await feature("ui-components");
9
+ await story("ReportGlobals");
10
+ await label("coverage", "ui-components");
11
+ });
4
12
 
5
13
  const environmentNames: Record<string, string> = {
6
14
  prod_env: "Prod",
@@ -1,6 +1,14 @@
1
1
  import { fireEvent, render, screen, waitFor } from "@testing-library/preact";
2
+ import { epic, feature, label, story } from "allure-js-commons";
2
3
  import { beforeEach, describe, expect, it, vi } from "vitest";
3
4
 
5
+ beforeEach(async () => {
6
+ await epic("coverage");
7
+ await feature("ui-components");
8
+ await story("PwTraceButton");
9
+ await label("coverage", "ui-components");
10
+ });
11
+
4
12
  type SetupOptions = {
5
13
  canOpenInNewTab: boolean;
6
14
  failFetch?: boolean;
@@ -1,6 +1,14 @@
1
1
  import { cleanup, fireEvent, render } from "@testing-library/preact";
2
+ import { epic, feature, label, story } from "allure-js-commons";
2
3
  import { beforeEach, describe, expect, it, vi } from "vitest";
3
4
 
5
+ beforeEach(async () => {
6
+ await epic("coverage");
7
+ await feature("ui-components");
8
+ await story("TrErrorStep");
9
+ await label("coverage", "ui-components");
10
+ });
11
+
4
12
  const { matchMediaMock } = vi.hoisted(() => {
5
13
  const matchMediaMock = vi.fn().mockImplementation(() => ({
6
14
  matches: false,
@@ -1,7 +1,15 @@
1
1
  import { cleanup, render, screen } from "@testing-library/preact";
2
+ import { epic, feature, label, story } from "allure-js-commons";
2
3
  import type { AwesomeTestResult } from "types";
3
4
  import { beforeEach, describe, expect, it, vi } from "vitest";
4
5
 
6
+ beforeEach(async () => {
7
+ await epic("coverage");
8
+ await feature("ui-components");
9
+ await story("TrOverview");
10
+ await label("coverage", "ui-components");
11
+ });
12
+
5
13
  import { TrOverview } from "@/components/TestResult/TrOverview";
6
14
 
7
15
  vi.mock("@/components/TestResult/TestStepsEmpty", () => ({
@@ -12,32 +20,36 @@ vi.mock("@/components/TestResult/TrSteps", () => ({
12
20
  TrSteps: () => <div data-testid="tr-steps" />,
13
21
  }));
14
22
 
23
+ vi.mock("@/components/TestResult/TrError", () => ({
24
+ TrError: () => <div data-testid="test-result-error" />,
25
+ }));
26
+
15
27
  vi.mock("@/components/TestResult/TrDescription", () => ({
16
- TrDescription: () => null,
28
+ TrDescription: () => null as any,
17
29
  }));
18
30
 
19
31
  vi.mock("@/components/TestResult/TrLinks", () => ({
20
- TrLinks: () => null,
32
+ TrLinks: () => null as any,
21
33
  }));
22
34
 
23
35
  vi.mock("@/components/TestResult/TrMetadata", () => ({
24
- TrMetadata: () => null,
36
+ TrMetadata: () => null as any,
25
37
  }));
26
38
 
27
39
  vi.mock("@/components/TestResult/TrParameters", () => ({
28
- TrParameters: () => null,
40
+ TrParameters: () => null as any,
29
41
  }));
30
42
 
31
43
  vi.mock("@/components/TestResult/TrPwTraces", () => ({
32
- TrPwTraces: () => null,
44
+ TrPwTraces: () => null as any,
33
45
  }));
34
46
 
35
47
  vi.mock("@/components/TestResult/TrSetup", () => ({
36
- TrSetup: () => null,
48
+ TrSetup: () => null as any,
37
49
  }));
38
50
 
39
51
  vi.mock("@/components/TestResult/TrTeardown", () => ({
40
- TrTeardown: () => null,
52
+ TrTeardown: () => null as any,
41
53
  }));
42
54
 
43
55
  vi.mock("@/stores/locale", () => ({
@@ -48,6 +60,7 @@ vi.mock("@/stores/locale", () => ({
48
60
 
49
61
  vi.mock("@/stores/testResult", () => ({
50
62
  currentTrId: { value: "current-test-result-id" },
63
+ trCurrentTab: { value: "overview" },
51
64
  }));
52
65
 
53
66
  const makeTestResult = (overrides: Partial<AwesomeTestResult> = {}): AwesomeTestResult =>
@@ -59,7 +72,7 @@ const makeTestResult = (overrides: Partial<AwesomeTestResult> = {}): AwesomeTest
59
72
  flaky: false,
60
73
  muted: false,
61
74
  known: false,
62
- hidden: false,
75
+ isRetry: false,
63
76
  labels: [],
64
77
  groupedLabels: {},
65
78
  parameters: [],
@@ -98,8 +111,15 @@ describe("components > TestResult > TrOverview", () => {
98
111
  expect(screen.queryByTestId("test-steps-empty")).not.toBeInTheDocument();
99
112
  });
100
113
 
101
- it("should render TrSteps when the test has an error", () => {
102
- render(<TrOverview testResult={makeTestResult({ error: { message: "boom" } })} />);
114
+ it("should render TrSteps when the test has steps and an error", () => {
115
+ render(
116
+ <TrOverview
117
+ testResult={makeTestResult({
118
+ error: { message: "boom" },
119
+ steps: [{ type: "step", name: "step", status: "passed", parameters: [], steps: [] }],
120
+ })}
121
+ />,
122
+ );
103
123
 
104
124
  expect(screen.getByTestId("tr-steps")).toBeInTheDocument();
105
125
  expect(screen.queryByTestId("test-steps-empty")).not.toBeInTheDocument();
@@ -0,0 +1,73 @@
1
+ import { cleanup, render } from "@testing-library/preact";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+
4
+ vi.hoisted(() => {
5
+ vi.stubGlobal(
6
+ "matchMedia",
7
+ vi.fn().mockImplementation(() => ({
8
+ matches: false,
9
+ media: "",
10
+ onchange: null,
11
+ addListener: vi.fn(),
12
+ removeListener: vi.fn(),
13
+ addEventListener: vi.fn(),
14
+ removeEventListener: vi.fn(),
15
+ dispatchEvent: vi.fn(),
16
+ })),
17
+ );
18
+ });
19
+
20
+ import type { TrBodyItem } from "@/components/TestResult/bodyItems";
21
+ import { TrSteps } from "@/components/TestResult/TrSteps";
22
+ import { collapsedTrees, expandedTrees } from "@/stores/tree";
23
+
24
+ const passedStep = {
25
+ type: "step",
26
+ item: {
27
+ stepId: "passed-step",
28
+ name: "passed step",
29
+ status: "passed",
30
+ parameters: [],
31
+ message: "",
32
+ trace: "",
33
+ hasSimilarErrorInSubSteps: false,
34
+ },
35
+ suppressInlineError: false,
36
+ bodyItems: [],
37
+ } satisfies TrBodyItem;
38
+
39
+ const failedStep = {
40
+ type: "step",
41
+ item: {
42
+ stepId: "failed-step",
43
+ name: "failed step",
44
+ status: "failed",
45
+ parameters: [],
46
+ message: "failed",
47
+ trace: "trace",
48
+ hasSimilarErrorInSubSteps: false,
49
+ },
50
+ suppressInlineError: false,
51
+ bodyItems: [],
52
+ } satisfies TrBodyItem;
53
+
54
+ describe("components > TestResult > TrSteps", () => {
55
+ beforeEach(() => {
56
+ cleanup();
57
+ collapsedTrees.value = new Set();
58
+ expandedTrees.value = new Set();
59
+ globalThis.allureReportOptions = { stepTreeExpansion: "expand_failed_only" } as any;
60
+ });
61
+
62
+ it("collapses passed-only root steps by default with expand_failed_only", () => {
63
+ const view = render(<TrSteps id="passed-test" bodyItems={[passedStep]} />);
64
+
65
+ expect(view.queryByTestId("test-result-steps-root")).not.toBeInTheDocument();
66
+ });
67
+
68
+ it("opens root steps by default when expand_failed_only finds failed context", () => {
69
+ const view = render(<TrSteps id="failed-test" bodyItems={[passedStep, failedStep]} />);
70
+
71
+ expect(view.getByTestId("test-result-steps-root")).toBeInTheDocument();
72
+ });
73
+ });
@@ -1,6 +1,14 @@
1
1
  import type { AttachmentTestStepResult, DefaultTestStepResult } from "@allurereport/core-api";
2
+ import { epic, feature, label, story } from "allure-js-commons";
2
3
  import type { AwesomeFixtureResult, AwesomeTestResult } from "types";
3
- import { describe, expect, it } from "vitest";
4
+ import { beforeEach, describe, expect, it } from "vitest";
5
+
6
+ beforeEach(async () => {
7
+ await epic("coverage");
8
+ await feature("ui-components");
9
+ await story("bodyItems");
10
+ await label("coverage", "ui-components");
11
+ });
4
12
 
5
13
  import {
6
14
  fixtureResultToTrStepItem,
@@ -1,5 +1,13 @@
1
+ import { epic, feature, label, story } from "allure-js-commons";
1
2
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
3
 
4
+ beforeEach(async () => {
5
+ await epic("coverage");
6
+ await feature("ui-components");
7
+ await story("openPwTraceInNewTab");
8
+ await label("coverage", "ui-components");
9
+ });
10
+
3
11
  describe("components > TestResult > openPlaywrightTraceInNewTab", () => {
4
12
  beforeEach(() => {
5
13
  vi.resetModules();
@@ -1,14 +1,22 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { getNextSubtreeToggleState } from "@allurereport/web-commons";
2
+ import { epic, feature, label, story } from "allure-js-commons";
3
+ import { beforeEach, describe, expect, it } from "vitest";
2
4
 
3
5
  import type { TrBodyItem } from "@/components/TestResult/bodyItems";
4
6
  import {
5
7
  collectExpandableStepNodes,
6
- getNextSubtreeToggleState,
7
8
  hasFailedStepContext,
8
9
  isOpenByDefaultForPolicy,
9
10
  isStepOpenedByDefault,
10
11
  } from "@/components/TestResult/TrSteps/stepTreeExpansion";
11
12
 
13
+ beforeEach(async () => {
14
+ await epic("coverage");
15
+ await feature("ui-components");
16
+ await story("stepTreeExpansion");
17
+ await label("coverage", "ui-components");
18
+ });
19
+
12
20
  describe("components > TestResult > stepTreeExpansion", () => {
13
21
  it("should detect failed context in nested steps", () => {
14
22
  const bodyItems = [
@@ -1,12 +1,20 @@
1
1
  import { signal } from "@preact/signals";
2
2
  import { cleanup, render, screen } from "@testing-library/preact";
3
+ import { epic, feature, label, story } from "allure-js-commons";
3
4
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
5
 
6
+ beforeEach(async () => {
7
+ await epic("coverage");
8
+ await feature("ui-components");
9
+ await story("Timeline");
10
+ await label("coverage", "ui-components");
11
+ });
12
+
5
13
  type TimelineTestResult = {
6
14
  id: string;
7
15
  name: string;
8
16
  status: "passed" | "failed";
9
- hidden: boolean;
17
+ isRetry: boolean;
10
18
  environment: string;
11
19
  environmentName?: string;
12
20
  host: string;
@@ -30,11 +38,11 @@ const setup = async (timelineData: TimelineTestResult[]) => {
30
38
  Timeline: ({ data, dataId }: { data: TimelineTestResult[]; dataId: string }) => (
31
39
  <div data-testid={`timeline-${dataId}`}>{data.map(({ id }) => id).join(",")}</div>
32
40
  ),
33
- Grid: ({ children }: { children: unknown }) => <div>{children}</div>,
34
- GridItem: ({ children }: { children: unknown }) => <div>{children}</div>,
35
- Loadable: ({ renderData }: { renderData: () => JSX.Element }) => renderData(),
41
+ Grid: ({ children }: { children: unknown }) => <div>{children as any}</div>,
42
+ GridItem: ({ children }: { children: unknown }) => <div>{children as any}</div>,
43
+ Loadable: ({ renderData }: { renderData: () => any }) => renderData(),
36
44
  PageLoader: () => <div>loading</div>,
37
- Widget: ({ children }: { children: unknown }) => <div>{children}</div>,
45
+ Widget: ({ children }: { children: unknown }) => <div>{children as any}</div>,
38
46
  }));
39
47
  vi.doMock("@/stores", () => ({
40
48
  useI18n: () => ({
@@ -76,7 +84,7 @@ describe("components > Timeline", () => {
76
84
  id: "tr-qa-a",
77
85
  name: "qa a test",
78
86
  status: "passed",
79
- hidden: false,
87
+ isRetry: false,
80
88
  environment: "qa_a",
81
89
  environmentName: "QA",
82
90
  host: "shared-host",
@@ -88,7 +96,7 @@ describe("components > Timeline", () => {
88
96
  id: "tr-qa-b",
89
97
  name: "qa b test",
90
98
  status: "failed",
91
- hidden: false,
99
+ isRetry: false,
92
100
  environment: "qa_b",
93
101
  environmentName: "QA",
94
102
  host: "shared-host",