@allurereport/web-awesome 3.8.2 → 3.10.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 (227) hide show
  1. package/README.md +112 -0
  2. package/allurerc-dev.mjs +10 -0
  3. package/dist/multi/121.app-b18cce138691927e8759.js +1 -0
  4. package/dist/multi/173.app-b18cce138691927e8759.js +1 -0
  5. package/dist/multi/174.app-b18cce138691927e8759.js +1 -0
  6. package/dist/multi/252.app-b18cce138691927e8759.js +1 -0
  7. package/dist/multi/282.app-b18cce138691927e8759.js +1 -0
  8. package/dist/multi/29.app-b18cce138691927e8759.js +1 -0
  9. package/dist/multi/310.app-b18cce138691927e8759.js +1 -0
  10. package/dist/multi/416.app-b18cce138691927e8759.js +1 -0
  11. package/dist/multi/507.app-b18cce138691927e8759.js +1 -0
  12. package/dist/multi/527.app-b18cce138691927e8759.js +1 -0
  13. package/dist/multi/600.app-b18cce138691927e8759.js +1 -0
  14. package/dist/multi/605.app-b18cce138691927e8759.js +1 -0
  15. package/dist/multi/638.app-b18cce138691927e8759.js +1 -0
  16. package/dist/multi/672.app-b18cce138691927e8759.js +1 -0
  17. package/dist/multi/686.app-b18cce138691927e8759.js +1 -0
  18. package/dist/multi/725.app-b18cce138691927e8759.js +1 -0
  19. package/dist/multi/741.app-b18cce138691927e8759.js +1 -0
  20. package/dist/multi/749.app-b18cce138691927e8759.js +1 -0
  21. package/dist/multi/755.app-b18cce138691927e8759.js +1 -0
  22. package/dist/multi/779.app-b18cce138691927e8759.js +1 -0
  23. package/dist/multi/894.app-b18cce138691927e8759.js +1 -0
  24. package/dist/multi/943.app-b18cce138691927e8759.js +1 -0
  25. package/dist/multi/980.app-b18cce138691927e8759.js +1 -0
  26. package/dist/multi/app-b18cce138691927e8759.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-5c882b14b6f3112e40c4.css +1 -0
  30. package/dist/multi/styles-a4f65de86208f79dd2be.css +58 -0
  31. package/dist/single/app-733f473da7b51f98876d.js +2 -0
  32. package/dist/single/manifest.json +1 -1
  33. package/package.json +19 -14
  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/FooterVersion.tsx +5 -10
  47. package/src/components/Footer/index.tsx +7 -1
  48. package/src/components/Footer/styles.scss +8 -2
  49. package/src/components/Header/CiInfo/index.tsx +17 -13
  50. package/src/components/Header/CiInfo/styles.scss +1 -1
  51. package/src/components/Header/styles.scss +2 -2
  52. package/src/components/HeaderControls/index.tsx +1 -3
  53. package/src/components/HotkeysProvider/index.tsx +556 -0
  54. package/src/components/KeyboardShortcuts/index.tsx +73 -0
  55. package/src/components/KeyboardShortcuts/shortcutsConfig.ts +91 -0
  56. package/src/components/KeyboardShortcuts/styles.scss +69 -0
  57. package/src/components/MainReport/index.tsx +89 -72
  58. package/src/components/MainReport/styles.scss +20 -5
  59. package/src/components/Metadata/index.tsx +27 -6
  60. package/src/components/Metadata/styles.scss +21 -9
  61. package/src/components/MetadataButton/index.tsx +2 -0
  62. package/src/components/MetadataButton/styles.scss +1 -1
  63. package/src/components/NavTabs/styles.scss +8 -8
  64. package/src/components/ReportBody/styles.scss +3 -4
  65. package/src/components/ReportCategories/styles.scss +1 -1
  66. package/src/components/ReportFilters/styles.scss +1 -1
  67. package/src/components/ReportGlobalAttachments/styles.scss +1 -1
  68. package/src/components/ReportGlobalErrors/styles.scss +1 -1
  69. package/src/components/ReportHeader/index.tsx +25 -13
  70. package/src/components/ReportHeader/styles.scss +2 -2
  71. package/src/components/ReportMetadata/index.tsx +44 -15
  72. package/src/components/ReportMetadata/styles.scss +6 -6
  73. package/src/components/ReportQualityGateResults/styles.scss +2 -2
  74. package/src/components/ReportSearch/index.tsx +1 -5
  75. package/src/components/ReportTabs/styles.scss +9 -9
  76. package/src/components/SectionSwitcher/index.tsx +87 -10
  77. package/src/components/SideBySide/index.tsx +20 -2
  78. package/src/components/SideBySide/styles.scss +9 -1
  79. package/src/components/SplitLayout/index.tsx +11 -2
  80. package/src/components/SplitLayout/styles.scss +23 -4
  81. package/src/components/TestResult/TestStepsEmpty/styles.scss +1 -1
  82. package/src/components/TestResult/TrDescription/styles.scss +1 -1
  83. package/src/components/TestResult/TrDropdown/index.tsx +2 -2
  84. package/src/components/TestResult/TrDropdown/styles.scss +1 -1
  85. package/src/components/TestResult/TrEmpty/styles.scss +1 -1
  86. package/src/components/TestResult/TrEnvironmentItem/styles.scss +4 -4
  87. package/src/components/TestResult/TrError/index.tsx +32 -7
  88. package/src/components/TestResult/TrError/styles.scss +23 -23
  89. package/src/components/TestResult/TrHeader/styles.scss +2 -2
  90. package/src/components/TestResult/TrHistory/styles.scss +6 -6
  91. package/src/components/TestResult/TrInfo/styles.scss +8 -8
  92. package/src/components/TestResult/TrLinks/index.tsx +2 -2
  93. package/src/components/TestResult/TrLinks/styles.scss +2 -2
  94. package/src/components/TestResult/TrMetadata/index.tsx +1 -1
  95. package/src/components/TestResult/TrMetadata/styles.scss +1 -1
  96. package/src/components/TestResult/TrNavigation/index.tsx +1 -1
  97. package/src/components/TestResult/TrNavigation/styles.scss +2 -2
  98. package/src/components/TestResult/TrOverview.tsx +2 -0
  99. package/src/components/TestResult/TrParameters/index.tsx +1 -1
  100. package/src/components/TestResult/TrParameters/styles.scss +1 -1
  101. package/src/components/TestResult/TrPrevStatuses/styles.scss +8 -8
  102. package/src/components/TestResult/TrPwTraces/styles.scss +1 -1
  103. package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +27 -1
  104. package/src/components/TestResult/TrRetriesView/styles.scss +20 -10
  105. package/src/components/TestResult/TrSetup/index.tsx +10 -4
  106. package/src/components/TestResult/TrSeverity/styles.scss +7 -7
  107. package/src/components/TestResult/TrStatus/styles.scss +2 -35
  108. package/src/components/TestResult/TrSteps/TrAttachment.tsx +79 -43
  109. package/src/components/TestResult/TrSteps/TrAttachmentInfo.tsx +44 -17
  110. package/src/components/TestResult/TrSteps/TrBodyItems.tsx +5 -2
  111. package/src/components/TestResult/TrSteps/TrErrorStep.tsx +3 -0
  112. package/src/components/TestResult/TrSteps/TrStep.tsx +15 -6
  113. package/src/components/TestResult/TrSteps/TrStepHeader.tsx +8 -5
  114. package/src/components/TestResult/TrSteps/index.tsx +7 -5
  115. package/src/components/TestResult/TrSteps/stepTreeExpansion.ts +27 -9
  116. package/src/components/TestResult/TrSteps/styles.scss +80 -20
  117. package/src/components/TestResult/TrTeardown/index.tsx +10 -4
  118. package/src/components/TestResult/bodyItems.ts +1 -1
  119. package/src/components/TestResult/index.tsx +8 -2
  120. package/src/components/TestResult/styles.scss +10 -1
  121. package/src/components/TestResult/trOverviewFocus.scss +4 -0
  122. package/src/components/Timeline/styles.scss +6 -6
  123. package/src/components/Tree/index.tsx +79 -5
  124. package/src/components/Tree/styles.scss +55 -35
  125. package/src/hooks/useTestResultOverviewFocusScroll.ts +23 -0
  126. package/src/index.html +30 -33
  127. package/src/index.tsx +12 -6
  128. package/src/locales/ar.json +62 -1
  129. package/src/locales/az.json +62 -1
  130. package/src/locales/de.json +62 -1
  131. package/src/locales/en.json +62 -1
  132. package/src/locales/es.json +62 -1
  133. package/src/locales/fr.json +62 -1
  134. package/src/locales/he.json +62 -1
  135. package/src/locales/hy.json +62 -1
  136. package/src/locales/it.json +62 -1
  137. package/src/locales/ja.json +62 -1
  138. package/src/locales/ka.json +62 -1
  139. package/src/locales/kr.json +62 -1
  140. package/src/locales/nl.json +62 -1
  141. package/src/locales/pl.json +62 -1
  142. package/src/locales/pt.json +62 -1
  143. package/src/locales/ru.json +62 -1
  144. package/src/locales/sv.json +62 -1
  145. package/src/locales/tr.json +62 -1
  146. package/src/locales/uk.json +62 -1
  147. package/src/locales/zh-TW.json +62 -1
  148. package/src/locales/zh.json +62 -1
  149. package/src/stores/keyboard.ts +371 -0
  150. package/src/stores/keyboardActions.ts +769 -0
  151. package/src/stores/locale.ts +5 -2
  152. package/src/stores/reportEnvSections.ts +6 -0
  153. package/src/stores/reportRootTabs.ts +95 -0
  154. package/src/stores/search.ts +147 -0
  155. package/src/stores/testResultOverviewNav.ts +119 -0
  156. package/src/stores/testResultTabs.ts +62 -0
  157. package/src/stores/timeline.ts +1 -1
  158. package/src/stores/tree.ts +42 -4
  159. package/src/stores/treeFilters/store.ts +3 -36
  160. package/src/stores/treeSort.ts +7 -1
  161. package/src/styles/_pane-active.scss +8 -0
  162. package/src/styles.scss +1 -1
  163. package/src/utils/atSeparator.ts +4 -0
  164. package/src/utils/flattenTestResultOverview.ts +182 -0
  165. package/src/utils/time.ts +2 -1
  166. package/src/utils/trOverviewFocus.ts +18 -0
  167. package/src/utils/treeFilters.ts +15 -4
  168. package/test/components/EnvironmentPicker.test.tsx +21 -3
  169. package/test/components/Footer.test.tsx +26 -0
  170. package/test/components/Header/CiInfo.test.tsx +56 -0
  171. package/test/components/Header.test.tsx +8 -0
  172. package/test/components/HeaderControls.test.tsx +28 -0
  173. package/test/components/ReportGlobals.test.tsx +9 -1
  174. package/test/components/ReportHeader.test.tsx +77 -0
  175. package/test/components/ReportMetadata.test.tsx +131 -0
  176. package/test/components/TestResult/PwTraceButton.test.tsx +8 -0
  177. package/test/components/TestResult/TrErrorStep.test.tsx +8 -0
  178. package/test/components/TestResult/TrOverview.test.tsx +30 -10
  179. package/test/components/TestResult/TrRetriesItem.test.tsx +163 -0
  180. package/test/components/TestResult/TrSteps.test.tsx +108 -0
  181. package/test/components/TestResult/bodyItems.test.ts +9 -1
  182. package/test/components/TestResult/openPwTraceInNewTab.test.ts +8 -0
  183. package/test/components/TestResult/stepTreeExpansion.test.ts +10 -2
  184. package/test/components/Timeline.test.tsx +15 -7
  185. package/test/stores/keyboard/keyboardActions.test.ts +615 -0
  186. package/test/stores/search.test.ts +143 -0
  187. package/test/stores/treeFilters/actions.test.ts +8 -0
  188. package/test/stores/treeSort.test.ts +58 -0
  189. package/test/utils/flattenTestResultOverview.test.ts +57 -0
  190. package/test/utils/ownerAddress.test.ts +9 -1
  191. package/test/utils/time.test.ts +52 -0
  192. package/test/utils/treeFilters.test.ts +113 -1
  193. package/types.d.ts +39 -0
  194. package/webpack.config.js +12 -7
  195. package/CONTRIBUTING.md +0 -34
  196. package/dist/multi/173.app-f008fb8342025f2b1ace.js +0 -1
  197. package/dist/multi/174.app-f008fb8342025f2b1ace.js +0 -1
  198. package/dist/multi/252.app-f008fb8342025f2b1ace.js +0 -1
  199. package/dist/multi/282.app-f008fb8342025f2b1ace.js +0 -1
  200. package/dist/multi/29.app-f008fb8342025f2b1ace.js +0 -1
  201. package/dist/multi/310.app-f008fb8342025f2b1ace.js +0 -1
  202. package/dist/multi/416.app-f008fb8342025f2b1ace.js +0 -1
  203. package/dist/multi/507.app-f008fb8342025f2b1ace.js +0 -1
  204. package/dist/multi/527.app-f008fb8342025f2b1ace.js +0 -1
  205. package/dist/multi/600.app-f008fb8342025f2b1ace.js +0 -1
  206. package/dist/multi/605.app-f008fb8342025f2b1ace.js +0 -1
  207. package/dist/multi/638.app-f008fb8342025f2b1ace.js +0 -1
  208. package/dist/multi/672.app-f008fb8342025f2b1ace.js +0 -1
  209. package/dist/multi/686.app-f008fb8342025f2b1ace.js +0 -1
  210. package/dist/multi/725.app-f008fb8342025f2b1ace.js +0 -1
  211. package/dist/multi/741.app-f008fb8342025f2b1ace.js +0 -1
  212. package/dist/multi/749.app-f008fb8342025f2b1ace.js +0 -1
  213. package/dist/multi/755.app-f008fb8342025f2b1ace.js +0 -1
  214. package/dist/multi/894.app-f008fb8342025f2b1ace.js +0 -1
  215. package/dist/multi/943.app-f008fb8342025f2b1ace.js +0 -1
  216. package/dist/multi/980.app-f008fb8342025f2b1ace.js +0 -1
  217. package/dist/multi/app-f008fb8342025f2b1ace.js +0 -2
  218. package/dist/multi/styles-9f7a23a0c8b79fa76981.css +0 -58
  219. package/dist/single/app-07332238da9897064301.js +0 -2
  220. package/src/assets/scss/day.scss +0 -53
  221. package/src/assets/scss/fonts.scss +0 -3
  222. package/src/assets/scss/night.scss +0 -63
  223. package/src/assets/scss/palette.scss +0 -393
  224. package/src/assets/scss/theme.scss +0 -330
  225. package/src/assets/scss/vars.scss +0 -11
  226. /package/dist/multi/{app-f008fb8342025f2b1ace.js.LICENSE.txt → app-b18cce138691927e8759.js.LICENSE.txt} +0 -0
  227. /package/dist/single/{app-07332238da9897064301.js.LICENSE.txt → app-733f473da7b51f98876d.js.LICENSE.txt} +0 -0
@@ -8,6 +8,7 @@ import { TrDropdown } from "@/components/TestResult/TrDropdown";
8
8
  import { TrStep } from "@/components/TestResult/TrSteps/TrStep";
9
9
  import { useI18n } from "@/stores/locale";
10
10
  import { collapsedTrees, toggleTree } from "@/stores/tree";
11
+ import { trOverviewFocusAttrs, trOverviewHeaderFocusClass } from "@/utils/trOverviewFocus";
11
12
 
12
13
  import * as styles from "@/components/TestResult/TrSteps/styles.scss";
13
14
 
@@ -17,19 +18,24 @@ export type TrSetupProps = {
17
18
  };
18
19
 
19
20
  export const TrSetup: FunctionalComponent<TrSetupProps> = ({ setup, id }) => {
20
- const teardownId = `${id}-setup`;
21
- const isEarlyCollapsed = Boolean(!collapsedTrees.value.has(teardownId));
21
+ const setupId = id ? `${id}-setup` : null;
22
+ const isEarlyCollapsed = setupId ? Boolean(!collapsedTrees.value.has(setupId)) : true;
22
23
  const [isOpened, setIsOpen] = useState<boolean>(isEarlyCollapsed);
23
24
 
24
25
  const handleClick = () => {
25
26
  setIsOpen(!isOpened);
26
- toggleTree(teardownId);
27
+
28
+ if (setupId) {
29
+ toggleTree(setupId);
30
+ }
27
31
  };
28
32
  const { t } = useI18n("execution");
29
33
 
30
34
  return (
31
35
  <div className={styles["test-result-steps"]}>
32
36
  <TrDropdown
37
+ className={trOverviewHeaderFocusClass(setupId)}
38
+ {...trOverviewFocusAttrs(setupId)}
33
39
  icon={allureIcons.lineTimeClockStopwatch}
34
40
  isOpened={isOpened}
35
41
  setIsOpen={handleClick}
@@ -40,7 +46,7 @@ export const TrSetup: FunctionalComponent<TrSetupProps> = ({ setup, id }) => {
40
46
  <div className={styles["test-result-steps-root"]}>
41
47
  {setup?.map((fixture, key) => (
42
48
  <div className={styles["test-result-step-root"]} key={fixture.id}>
43
- <TrStep item={fixtureResultToTrStepItem(fixture)} stepIndex={key + 1} />
49
+ <TrStep item={fixtureResultToTrStepItem(fixture)} stepIndex={key + 1} isTopLevel={true} />
44
50
  </div>
45
51
  ))}
46
52
  </div>
@@ -2,29 +2,29 @@
2
2
  display: flex;
3
3
  align-items: center;
4
4
  gap: 6px;
5
- color: var(--on-text-secondary);
5
+ color: var(--color-text-secondary);
6
6
  }
7
7
 
8
8
  .test-result-severity-text {
9
- color: var(--on-text-secondary);
9
+ color: var(--color-text-secondary);
10
10
  }
11
11
 
12
12
  .severity-blocker {
13
- color: var(--on-support-capella);
13
+ color: var(--color-intent-danger-text);
14
14
  }
15
15
 
16
16
  .severity-critical {
17
- color: var(--on-support-atlas);
17
+ color: var(--color-intent-warning-text);
18
18
  }
19
19
 
20
20
  .severity-normal {
21
- color: var(--on-icon-secondary);
21
+ color: var(--color-icon-secondary);
22
22
  }
23
23
 
24
24
  .severity-minor {
25
- color: var(--on-support-aldebaran);
25
+ color: var(--color-intent-primary-text);
26
26
  }
27
27
 
28
28
  .severity-trivial {
29
- color: var(--on-support-castor);
29
+ color: var(--color-intent-success-text);
30
30
  }
@@ -1,36 +1,3 @@
1
- .test-result-status {
2
- padding: 2px;
3
- display: flex;
4
- border-radius: 100px;
5
- color: var(--constant-on-text-primary);
6
- height: max-content;
7
- }
1
+ @import "~@allurereport/web-components/mixins.scss";
8
2
 
9
- .test-result-status-text {
10
- padding: 0 4px;
11
- }
12
-
13
- .test-result-status-icon {
14
- color: var(--constant-on-text-primary);
15
- padding: 0;
16
- }
17
-
18
- .status-passed {
19
- background-color: var(--bg-support-castor);
20
- }
21
-
22
- .status-failed {
23
- background-color: var(--bg-support-capella);
24
- }
25
-
26
- .status-broken {
27
- background-color: var(--bg-support-atlas);
28
- }
29
-
30
- .status-skipped {
31
- background-color: var(--bg-support-rau);
32
- }
33
-
34
- .status-unknown {
35
- background-color: var(--bg-support-skat);
36
- }
3
+ @include status-label-shape("test-result-status", "test-result-status-icon", "test-result-status-text");
@@ -1,5 +1,5 @@
1
1
  import type { AttachmentTestStepResult } from "@allurereport/core-api";
2
- import { attachmentType, isPreviewableContentType, isSyntaxHighlightSupported } from "@allurereport/web-commons";
2
+ import { attachmentType, isSyntaxHighlightSupported } from "@allurereport/web-commons";
3
3
  import { ArrowButton, Attachment, Code, SvgIcon, Text, allureIcons } from "@allurereport/web-components";
4
4
  import cx from "clsx";
5
5
  import type { FunctionComponent } from "preact";
@@ -9,6 +9,7 @@ import { TrAttachmentInfo } from "@/components/TestResult/TrSteps/TrAttachmentIn
9
9
  import { useI18n } from "@/stores";
10
10
  import { openModal } from "@/stores/modal";
11
11
  import { isTreeOpened, toggleTree } from "@/stores/tree";
12
+ import { trOverviewFocusAttrs, trOverviewHeaderFocusClass } from "@/utils/trOverviewFocus";
12
13
 
13
14
  import * as styles from "@/components/TestResult/TrSteps/styles.scss";
14
15
 
@@ -52,75 +53,112 @@ const iconMap: Record<string, string> = {
52
53
  "video/mp4": lineImagesImage,
53
54
  "application/vnd.allure.image.diff": lineImagesImage,
54
55
  "application/vnd.allure.playwright-trace": playwrightLogo,
56
+ "application/vnd.allure.http+json": lineFilesFileAttachment2,
55
57
  };
56
58
 
57
- const HAS_PREVIEW_COMPONENT = new Set(["html"]);
59
+ const HAS_PREVIEW_COMPONENT = new Set(["html", "markdown"]);
60
+ const DEFAULT_PREVIEW_TYPES = new Set(["markdown", "html"]);
58
61
 
59
62
  export const TrAttachment: FunctionComponent<{
60
63
  item: AttachmentTestStepResult;
61
64
  stepIndex?: number;
62
65
  className?: string;
63
66
  }> = ({ item, stepIndex }) => {
67
+ const { link } = item;
64
68
  const attachmentTreeId = item.link?.id !== null ? `attachment-${item.link.id}` : null;
65
69
  const isOpened = attachmentTreeId !== null ? isTreeOpened(attachmentTreeId, false) : false;
66
- const [showPreview, setShowPreview] = useState(false);
70
+ const componentTypeForPreview = attachmentType(link.contentType);
71
+ const [showPreview, setShowPreview] = useState(() => DEFAULT_PREVIEW_TYPES.has(componentTypeForPreview ?? ""));
67
72
  const [highlightCode, setHighlightCode] = useState(true);
68
73
  const { t: tAttachments } = useI18n("attachments");
69
- const { link } = item;
70
74
  const { missed } = link;
71
- const componentType = attachmentType(link.contentType);
75
+ const componentType = componentTypeForPreview;
72
76
  const isValidComponentType = !["archive", null].includes(componentType);
73
77
  const isPreviewable = HAS_PREVIEW_COMPONENT.has(componentType ?? "");
74
- const isCodeView = (componentType === "code" || componentType === "text") && (!isPreviewable || !showPreview);
78
+ const isImageAttachment = componentType === "image";
75
79
  const isSyntaxHighlightable = isSyntaxHighlightSupported({
76
80
  contentType: link.contentType,
77
81
  ext: link.ext,
78
82
  name: link.name,
79
83
  originalFileName: link.originalFileName,
80
84
  });
85
+ const supportsSyntaxHighlightToggle =
86
+ isSyntaxHighlightable &&
87
+ (componentType === "code" || componentType === "text" || componentType === "markdown" || componentType === "html");
81
88
 
82
- const expandAttachment = (event: Event) => {
89
+ const handleHighlightToggle = () => {
90
+ if (isPreviewable && showPreview) {
91
+ setShowPreview(false);
92
+ }
93
+ setHighlightCode((highlight) => !highlight);
94
+ };
95
+
96
+ const toggleAttachment = (event: Event) => {
83
97
  event.stopPropagation();
84
- if (componentType !== "image") {
85
- return;
98
+ if (attachmentTreeId !== null) {
99
+ toggleTree(attachmentTreeId, false);
86
100
  }
101
+ };
102
+
103
+ const expandAttachment = (event: Event) => {
104
+ event.stopPropagation();
87
105
  openModal({
88
106
  data: item,
89
107
  component: <Attachment item={item} previewable={true} />,
90
108
  });
91
109
  };
92
110
 
111
+ const content = (
112
+ <Attachment
113
+ item={item}
114
+ previewable={showPreview}
115
+ highlightCode={highlightCode}
116
+ i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }}
117
+ />
118
+ );
119
+
120
+ const attachmentHeaderContent = (
121
+ <>
122
+ {isValidComponentType ? (
123
+ <ArrowButton isOpened={isOpened} tag="span" />
124
+ ) : (
125
+ <span className={styles["test-result-strut"]} />
126
+ )}
127
+ <span className={styles["test-result-attachment-icon"]}>
128
+ <SvgIcon size="s" id={iconMap[link.contentType] ?? lineFilesFileAttachment2} />
129
+ </span>
130
+
131
+ <Code size="s" className={styles["test-result-step-number"]}>
132
+ {stepIndex}
133
+ </Code>
134
+ <Text className={styles["test-result-attachment-text"]}>{link.name || link.originalFileName}</Text>
135
+ {missed && (
136
+ <Text
137
+ size={"s"}
138
+ className={styles["test-result-attachment-missed"]}
139
+ data-testid={"test-result-attachment-missed"}
140
+ >
141
+ missed
142
+ </Text>
143
+ )}
144
+ </>
145
+ );
146
+
93
147
  return (
94
148
  <div data-testid={"test-result-attachment"} className={styles["test-result-step"]}>
95
149
  <div
96
150
  data-testid={"test-result-attachment-header"}
97
- className={cx(styles["test-result-attachment-header"], {
151
+ className={cx(styles["test-result-attachment-header"], trOverviewHeaderFocusClass(item.link.id), {
98
152
  [styles.empty]: !isValidComponentType,
99
153
  })}
100
- onClick={(e) => {
101
- e.stopPropagation();
102
- if (attachmentTreeId !== null) {
103
- toggleTree(attachmentTreeId, false);
104
- }
105
- }}
154
+ {...trOverviewFocusAttrs(item.link.id)}
106
155
  >
107
- {isValidComponentType ? <ArrowButton isOpened={isOpened} /> : <div className={styles["test-result-strut"]} />}
108
- <div className={styles["test-result-attachment-icon"]}>
109
- <SvgIcon size="s" id={iconMap[link.contentType] ?? lineFilesFileAttachment2} />
110
- </div>
111
-
112
- <Code size="s" className={styles["test-result-step-number"]}>
113
- {stepIndex}
114
- </Code>
115
- <Text className={styles["test-result-attachment-text"]}>{link.name || link.originalFileName}</Text>
116
- {missed && (
117
- <Text
118
- size={"s"}
119
- className={styles["test-result-attachment-missed"]}
120
- data-testid={"test-result-attachment-missed"}
121
- >
122
- missed
123
- </Text>
156
+ {isValidComponentType ? (
157
+ <button className={styles["test-result-attachment-toggle"]} onClick={toggleAttachment} type="button">
158
+ {attachmentHeaderContent}
159
+ </button>
160
+ ) : (
161
+ attachmentHeaderContent
124
162
  )}
125
163
  <div>
126
164
  <TrAttachmentInfo
@@ -129,22 +167,20 @@ export const TrAttachment: FunctionComponent<{
129
167
  isPreviewable={isPreviewable}
130
168
  showPreview={showPreview}
131
169
  onPreviewToggle={isPreviewable ? () => setShowPreview((p) => !p) : undefined}
132
- isCodeView={isCodeView && isSyntaxHighlightable}
133
170
  highlightCode={highlightCode}
134
- onHighlightToggle={isCodeView && isSyntaxHighlightable ? () => setHighlightCode((h) => !h) : undefined}
171
+ onHighlightToggle={supportsSyntaxHighlightToggle ? handleHighlightToggle : undefined}
135
172
  />
136
173
  </div>
137
174
  </div>
138
175
  {isOpened && isValidComponentType && (
139
176
  <div className={styles["test-result-attachment-content-wrapper"]}>
140
- <div className={styles["test-result-attachment-content"]} role={"button"} onClick={expandAttachment}>
141
- <Attachment
142
- item={item}
143
- previewable={showPreview}
144
- highlightCode={highlightCode}
145
- i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }}
146
- />
147
- </div>
177
+ {isImageAttachment ? (
178
+ <button className={styles["test-result-attachment-content"]} onClick={expandAttachment} type="button">
179
+ {content}
180
+ </button>
181
+ ) : (
182
+ <div className={styles["test-result-attachment-content"]}>{content}</div>
183
+ )}
148
184
  </div>
149
185
  )}
150
186
  </div>
@@ -18,7 +18,6 @@ interface TrAttachmentInfo {
18
18
  isPreviewable?: boolean;
19
19
  showPreview?: boolean;
20
20
  onPreviewToggle?: () => void;
21
- isCodeView?: boolean;
22
21
  highlightCode?: boolean;
23
22
  onHighlightToggle?: () => void;
24
23
  }
@@ -29,7 +28,6 @@ export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({
29
28
  isPreviewable,
30
29
  showPreview,
31
30
  onPreviewToggle,
32
- isCodeView,
33
31
  highlightCode = true,
34
32
  onHighlightToggle,
35
33
  }) => {
@@ -81,28 +79,57 @@ export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({
81
79
  <div className={styles["item-buttons"]}>
82
80
  {isPwTrace && <PwTraceButton link={item.link} />}
83
81
  {isPreviewable && onPreviewToggle && (
84
- <TooltipWrapper tooltipText={tooltip(showPreview ? "viewCode" : "previewAttachment")}>
85
- <IconButton
86
- className={styles["item-button"]}
87
- style={"ghost"}
88
- size={"s"}
89
- iconSize={"s"}
90
- icon={showPreview ? allureIcons.viewOff : allureIcons.view}
91
- onClick={(e: Event) => {
92
- e.stopPropagation();
93
- onPreviewToggle();
94
- }}
95
- />
96
- </TooltipWrapper>
82
+ <>
83
+ <TooltipWrapper tooltipText={tooltip("previewAttachment")}>
84
+ <IconButton
85
+ className={cx(styles["item-button"], showPreview && styles["item-button-active"])}
86
+ style={"ghost"}
87
+ size={"s"}
88
+ iconSize={"s"}
89
+ isActive={showPreview}
90
+ icon={allureIcons.view}
91
+ aria-pressed={showPreview}
92
+ onClick={(e: Event) => {
93
+ e.stopPropagation();
94
+ if (!showPreview) {
95
+ onPreviewToggle();
96
+ }
97
+ }}
98
+ />
99
+ </TooltipWrapper>
100
+ <TooltipWrapper tooltipText={tooltip("viewCode")}>
101
+ <IconButton
102
+ className={cx(styles["item-button"], !showPreview && styles["item-button-active"])}
103
+ style={"ghost"}
104
+ size={"s"}
105
+ iconSize={"s"}
106
+ isActive={!showPreview}
107
+ icon={allureIcons.lineFilesFileAttachment2}
108
+ aria-pressed={!showPreview}
109
+ onClick={(e: Event) => {
110
+ e.stopPropagation();
111
+ if (showPreview) {
112
+ onPreviewToggle();
113
+ }
114
+ }}
115
+ />
116
+ </TooltipWrapper>
117
+ </>
97
118
  )}
98
- {isCodeView && onHighlightToggle && (
119
+ {onHighlightToggle && (
99
120
  <TooltipWrapper tooltipText={tooltip("syntaxHighlight")}>
100
121
  <IconButton
101
- className={cx(styles["item-button"], !highlightCode && styles["item-button-syntax-off"])}
122
+ className={cx(
123
+ styles["item-button"],
124
+ highlightCode && styles["item-button-active"],
125
+ !highlightCode && styles["item-button-syntax-off"],
126
+ )}
102
127
  style={"ghost"}
103
128
  size={"s"}
104
129
  iconSize={"s"}
130
+ isActive={highlightCode}
105
131
  icon={allureIcons.lineDevCodeSquare}
132
+ aria-pressed={highlightCode}
106
133
  onClick={(e: Event) => {
107
134
  e.stopPropagation();
108
135
  onHighlightToggle();
@@ -20,15 +20,18 @@ const getBodyItemKey = (item: TrBodyItem, index: number) => {
20
20
 
21
21
  export type TrBodyItemsProps = {
22
22
  bodyItems: TrBodyItem[];
23
+ isTopLevel?: boolean;
23
24
  };
24
25
 
25
- export const TrBodyItems: FunctionalComponent<TrBodyItemsProps> = ({ bodyItems }) => {
26
+ export const TrBodyItems: FunctionalComponent<TrBodyItemsProps> = ({ bodyItems, isTopLevel }) => {
26
27
  return (
27
28
  <>
28
29
  {bodyItems.map((item, index) => {
29
30
  switch (item.type) {
30
31
  case "step":
31
- return <TrStep item={item} stepIndex={index + 1} key={getBodyItemKey(item, index)} />;
32
+ return (
33
+ <TrStep item={item} stepIndex={index + 1} isTopLevel={isTopLevel} key={getBodyItemKey(item, index)} />
34
+ );
32
35
  case "attachment":
33
36
  return <TrAttachment item={item} stepIndex={index + 1} key={getBodyItemKey(item, index)} />;
34
37
  case "error":
@@ -9,6 +9,7 @@ import {
9
9
  } from "@/components/TestResult/TrSteps/stepTreeExpansion";
10
10
  import { TrStepHeader } from "@/components/TestResult/TrSteps/TrStepHeader";
11
11
  import { isTreeOpened, toggleTree } from "@/stores/tree";
12
+ import { trOverviewFocusAttrs, trOverviewHeaderFocusClass } from "@/utils/trOverviewFocus";
12
13
 
13
14
  import * as styles from "@/components/TestResult/TrSteps/styles.scss";
14
15
 
@@ -26,6 +27,8 @@ export const TrErrorStep: FunctionComponent<TrErrorStepProps> = ({ item, stepInd
26
27
  return (
27
28
  <div data-testid="test-result-step" className={styles["test-result-step"]}>
28
29
  <TrStepHeader
30
+ className={trOverviewHeaderFocusClass(item.id)}
31
+ {...trOverviewFocusAttrs(item.id)}
29
32
  title={item.title}
30
33
  status={item.status}
31
34
  stepIndex={stepIndex}
@@ -1,3 +1,9 @@
1
+ import {
2
+ getNextSubtreeToggleState,
3
+ getSubtreeToggleIcon,
4
+ isSubtreeFirstLevelOnlyOpened,
5
+ type SubtreeToggleState,
6
+ } from "@allurereport/web-commons";
1
7
  import { IconButton, allureIcons } from "@allurereport/web-components";
2
8
  import type { FunctionComponent } from "preact";
3
9
  import { useState } from "preact/hooks";
@@ -10,17 +16,15 @@ import {
10
16
  collectExpandableStepNodes,
11
17
  hasStepContent,
12
18
  getStepTreeExpansionPolicy,
13
- getNextSubtreeToggleState,
14
- getSubtreeToggleIcon,
15
- isSubtreeFirstLevelOnlyOpened,
19
+ isOpenByDefaultForPolicy,
16
20
  isStepOpenedByDefault,
17
21
  type SubtreeNode,
18
- type SubtreeToggleState,
19
22
  } from "@/components/TestResult/TrSteps/stepTreeExpansion";
20
23
  import { TrBodyItems } from "@/components/TestResult/TrSteps/TrBodyItems";
21
24
  import { TrStepHeader } from "@/components/TestResult/TrSteps/TrStepHeader";
22
25
  import { TrStepInfo } from "@/components/TestResult/TrSteps/TrStepInfo";
23
26
  import { isTreeOpened, setTreeOpened, toggleTree } from "@/stores/tree";
27
+ import { trOverviewFocusAttrs, trOverviewHeaderFocusClass } from "@/utils/trOverviewFocus";
24
28
 
25
29
  import * as styles from "@/components/TestResult/TrSteps/styles.scss";
26
30
 
@@ -67,7 +71,8 @@ export const TrStepsContent = (props: { item: TrStepItem }) => {
67
71
  export const TrStep: FunctionComponent<{
68
72
  item: TrStepItem;
69
73
  stepIndex?: number;
70
- }> = ({ item, stepIndex }) => {
74
+ isTopLevel?: boolean;
75
+ }> = ({ item, stepIndex, isTopLevel }) => {
71
76
  const { item: stepData, bodyItems, suppressInlineError } = item;
72
77
  const inlineError = {
73
78
  message: stepData.message ?? stepData.error?.message,
@@ -82,7 +87,9 @@ export const TrStep: FunctionComponent<{
82
87
  );
83
88
  const policy = getStepTreeExpansionPolicy();
84
89
  const hasContent = hasStepContent(item);
85
- const openedByDefault = isStepOpenedByDefault(policy, stepData.status, bodyItems);
90
+ const openedByDefault = isTopLevel
91
+ ? isOpenByDefaultForPolicy(policy, true)
92
+ : isStepOpenedByDefault(policy, stepData.status, bodyItems);
86
93
  const isOpened = isTreeOpened(stepData.stepId, openedByDefault);
87
94
  const expandableDescendantNodes = collectExpandableStepNodes(bodyItems, policy);
88
95
  const hasExpandableDescendants = expandableDescendantNodes.length > 0;
@@ -143,6 +150,8 @@ export const TrStep: FunctionComponent<{
143
150
  return (
144
151
  <div data-testid={"test-result-step"} className={styles["test-result-step"]}>
145
152
  <TrStepHeader
153
+ className={trOverviewHeaderFocusClass(stepData.stepId)}
154
+ {...trOverviewFocusAttrs(stepData.stepId)}
146
155
  title={stepData.name}
147
156
  status={stepData.status}
148
157
  stepIndex={stepIndex}
@@ -1,5 +1,6 @@
1
1
  import type { TestStatus } from "@allurereport/core-api";
2
- import { ArrowButton, Code, Text, TreeItemIcon, allureIcons } from "@allurereport/web-components";
2
+ import { ArrowButton, Code, LinkifiedText, TreeItemIcon, allureIcons } from "@allurereport/web-components";
3
+ import clsx from "clsx";
3
4
  import type { FunctionComponent } from "preact";
4
5
 
5
6
  import * as styles from "@/components/TestResult/TrSteps/styles.scss";
@@ -13,6 +14,7 @@ export type TrStepHeaderProps = {
13
14
  onToggle: () => void;
14
15
  extra?: preact.ComponentChildren;
15
16
  subtreeToggle?: preact.ComponentChildren;
17
+ className?: string;
16
18
  };
17
19
 
18
20
  export const TrStepHeader: FunctionComponent<TrStepHeaderProps> = ({
@@ -24,11 +26,14 @@ export const TrStepHeader: FunctionComponent<TrStepHeaderProps> = ({
24
26
  onToggle,
25
27
  extra,
26
28
  subtreeToggle,
29
+ className,
30
+ ...rest
27
31
  }) => (
28
32
  <div
29
33
  data-testid="test-result-step-header"
30
- className={styles["test-result-step-header"]}
34
+ className={clsx(styles["test-result-step-header"], className)}
31
35
  onClick={hasContent ? onToggle : undefined}
36
+ {...rest}
32
37
  >
33
38
  {!hasContent ? (
34
39
  <div className={styles["test-result-strut"]} />
@@ -44,9 +49,7 @@ export const TrStepHeader: FunctionComponent<TrStepHeaderProps> = ({
44
49
  <Code size="s" className={styles["test-result-step-number"]}>
45
50
  {stepIndex}
46
51
  </Code>
47
- <Text data-testid="test-result-step-title" className={styles["test-result-header-text"]}>
48
- {title}
49
- </Text>
52
+ <LinkifiedText data-testid="test-result-step-title" className={styles["test-result-header-text"]} text={title} />
50
53
  {subtreeToggle}
51
54
  {extra}
52
55
  </div>
@@ -1,3 +1,4 @@
1
+ import { getNextSubtreeToggleState, getSubtreeToggleIcon, type SubtreeToggleState } from "@allurereport/web-commons";
1
2
  import { IconButton, allureIcons } from "@allurereport/web-components";
2
3
  import type { FunctionalComponent } from "preact";
3
4
  import { useState } from "preact/hooks";
@@ -6,16 +7,15 @@ import type { TrBodyItem } from "@/components/TestResult/bodyItems";
6
7
  import { TrDropdown } from "@/components/TestResult/TrDropdown";
7
8
  import {
8
9
  collectExpandableStepNodes,
9
- getNextSubtreeToggleState,
10
- getSubtreeToggleIcon,
11
10
  getStepTreeExpansionPolicy,
11
+ isOpenByDefaultForPolicy,
12
12
  isSubtreeFirstLevelOnlyOpened,
13
13
  type SubtreeNode,
14
- type SubtreeToggleState,
15
14
  } from "@/components/TestResult/TrSteps/stepTreeExpansion";
16
15
  import { TrBodyItems } from "@/components/TestResult/TrSteps/TrBodyItems";
17
16
  import { useI18n } from "@/stores/locale";
18
17
  import { isTreeOpened, setTreeOpened, toggleTree } from "@/stores/tree";
18
+ import { trOverviewFocusAttrs, trOverviewHeaderFocusClass } from "@/utils/trOverviewFocus";
19
19
 
20
20
  import * as styles from "./styles.scss";
21
21
 
@@ -34,7 +34,7 @@ export type TrStepsProps = {
34
34
  export const TrSteps: FunctionalComponent<TrStepsProps> = ({ bodyItems, id }) => {
35
35
  const stepsId = typeof id === "string" ? `${id}-steps` : null;
36
36
  const policy = getStepTreeExpansionPolicy();
37
- const isRootOpenedByDefault = policy !== "collapsed";
37
+ const isRootOpenedByDefault = isOpenByDefaultForPolicy(policy, true);
38
38
  const isOpened = stepsId !== null ? isTreeOpened(stepsId, isRootOpenedByDefault) : isRootOpenedByDefault;
39
39
  const expandableTreeNodes = collectExpandableStepNodes(bodyItems, policy);
40
40
  const hasChildren = stepsId !== null && bodyItems.length > 0;
@@ -96,6 +96,8 @@ export const TrSteps: FunctionalComponent<TrStepsProps> = ({ bodyItems, id }) =>
96
96
  return (
97
97
  <div className={styles["test-result-steps"]}>
98
98
  <TrDropdown
99
+ className={trOverviewHeaderFocusClass(stepsId)}
100
+ {...trOverviewFocusAttrs(stepsId)}
99
101
  icon={allureIcons.lineHelpersPlayCircle}
100
102
  isOpened={isOpened}
101
103
  setIsOpen={toggleRoot}
@@ -115,7 +117,7 @@ export const TrSteps: FunctionalComponent<TrStepsProps> = ({ bodyItems, id }) =>
115
117
  />
116
118
  {isOpened && (
117
119
  <div data-testid="test-result-steps-root" className={styles["test-result-steps-root"]}>
118
- <TrBodyItems bodyItems={bodyItems} />
120
+ <TrBodyItems bodyItems={bodyItems} isTopLevel={true} />
119
121
  </div>
120
122
  )}
121
123
  </div>
@@ -1,12 +1,5 @@
1
1
  import type { TestStatus } from "@allurereport/core-api";
2
- import { getReportOptions } from "@allurereport/web-commons";
3
- import {
4
- getNextSubtreeToggleState,
5
- getSubtreeToggleIcon,
6
- isSubtreeFirstLevelOnlyOpened,
7
- type SubtreeNodeState,
8
- type SubtreeToggleState,
9
- } from "@allurereport/web-commons";
2
+ import { getReportOptions, type SubtreeNodeState } from "@allurereport/web-commons";
10
3
 
11
4
  import { hasTestLevelErrorContent, type TrBodyItem, type TrStepItem } from "@/components/TestResult/bodyItems";
12
5
 
@@ -54,6 +47,26 @@ export type ExpandableStepNode = {
54
47
 
55
48
  export type SubtreeNode = SubtreeNodeState;
56
49
 
50
+ export const findStepBodyItems = (bodyItems: TrBodyItem[], stepId: string): TrBodyItem[] | null => {
51
+ for (const bodyItem of bodyItems) {
52
+ if (bodyItem.type !== "step") {
53
+ continue;
54
+ }
55
+
56
+ if (bodyItem.item.stepId === stepId) {
57
+ return bodyItem.bodyItems;
58
+ }
59
+
60
+ const nested = findStepBodyItems(bodyItem.bodyItems, stepId);
61
+
62
+ if (nested) {
63
+ return nested;
64
+ }
65
+ }
66
+
67
+ return null;
68
+ };
69
+
57
70
  export const collectExpandableStepNodes = (
58
71
  bodyItems: TrBodyItem[],
59
72
  policy: StepTreeExpansion,
@@ -83,7 +96,12 @@ export const collectExpandableStepNodes = (
83
96
  return nodes;
84
97
  };
85
98
 
86
- export { getNextSubtreeToggleState, getSubtreeToggleIcon, isSubtreeFirstLevelOnlyOpened, type SubtreeToggleState };
99
+ export {
100
+ getNextSubtreeToggleState,
101
+ getSubtreeToggleIcon,
102
+ isSubtreeFirstLevelOnlyOpened,
103
+ type SubtreeToggleState,
104
+ } from "@allurereport/web-commons";
87
105
 
88
106
  export const getStepTreeExpansionPolicy = (): StepTreeExpansion =>
89
107
  getReportOptions<AwesomeReportOptions>()?.stepTreeExpansion ?? DEFAULT_STEP_TREE_EXPANSION_POLICY;