@allurereport/web-awesome 3.3.1 → 3.4.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 (209) hide show
  1. package/dist/multi/173.app-648d4a8e7d5405e104a1.js +1 -0
  2. package/dist/multi/174.app-648d4a8e7d5405e104a1.js +1 -0
  3. package/dist/multi/252.app-648d4a8e7d5405e104a1.js +1 -0
  4. package/dist/multi/282.app-648d4a8e7d5405e104a1.js +1 -0
  5. package/dist/multi/29.app-648d4a8e7d5405e104a1.js +1 -0
  6. package/dist/multi/310.app-648d4a8e7d5405e104a1.js +1 -0
  7. package/dist/multi/416.app-648d4a8e7d5405e104a1.js +1 -0
  8. package/dist/multi/507.app-648d4a8e7d5405e104a1.js +1 -0
  9. package/dist/multi/527.app-648d4a8e7d5405e104a1.js +1 -0
  10. package/dist/multi/600.app-648d4a8e7d5405e104a1.js +1 -0
  11. package/dist/multi/605.app-648d4a8e7d5405e104a1.js +1 -0
  12. package/dist/multi/638.app-648d4a8e7d5405e104a1.js +1 -0
  13. package/dist/multi/672.app-648d4a8e7d5405e104a1.js +1 -0
  14. package/dist/multi/686.app-648d4a8e7d5405e104a1.js +1 -0
  15. package/dist/multi/725.app-648d4a8e7d5405e104a1.js +1 -0
  16. package/dist/multi/741.app-648d4a8e7d5405e104a1.js +1 -0
  17. package/dist/multi/749.app-648d4a8e7d5405e104a1.js +1 -0
  18. package/dist/multi/755.app-648d4a8e7d5405e104a1.js +1 -0
  19. package/dist/multi/{894.app-8be6acc0a596a2197dbf.js → 894.app-648d4a8e7d5405e104a1.js} +1 -1
  20. package/dist/multi/943.app-648d4a8e7d5405e104a1.js +1 -0
  21. package/dist/multi/980.app-648d4a8e7d5405e104a1.js +1 -0
  22. package/dist/multi/app-648d4a8e7d5405e104a1.js +2 -0
  23. package/dist/multi/{app-8be6acc0a596a2197dbf.js.LICENSE.txt → app-648d4a8e7d5405e104a1.js.LICENSE.txt} +1 -1
  24. package/dist/multi/manifest.json +23 -21
  25. package/dist/multi/{styles-0b84e1ef76554ad2db9a.css → styles-b72a0161ddf41447b31c.css} +10 -10
  26. package/dist/single/app-ae966ad3dc27579d6c39.js +2 -0
  27. package/dist/single/{app-8221eb856e47b4ef50d6.js.LICENSE.txt → app-ae966ad3dc27579d6c39.js.LICENSE.txt} +1 -1
  28. package/dist/single/manifest.json +1 -1
  29. package/package.json +18 -36
  30. package/src/components/BaseLayout/index.tsx +2 -0
  31. package/src/components/Categories/CategoriesTree/index.tsx +2 -0
  32. package/src/components/Categories/CategoryHeaderItem/index.tsx +2 -0
  33. package/src/components/Categories/CategoryTreeItem/index.tsx +2 -0
  34. package/src/components/Categories/GroupTreeItem/index.tsx +2 -0
  35. package/src/components/Categories/HistoryTreeItem/index.tsx +2 -0
  36. package/src/components/Categories/LabelTreeItem/index.tsx +2 -0
  37. package/src/components/Categories/MessageTreeItem/index.tsx +2 -0
  38. package/src/components/Categories/SeverityTreeItem/index.tsx +2 -0
  39. package/src/components/Charts/index.tsx +3 -0
  40. package/src/components/EnvironmentPicker/index.tsx +78 -18
  41. package/src/components/EnvironmentPicker/styles.scss +19 -0
  42. package/src/components/Footer/FooterLogo.tsx +1 -0
  43. package/src/components/Footer/FooterVersion.tsx +2 -0
  44. package/src/components/Footer/index.tsx +3 -1
  45. package/src/components/Header/CiInfo/index.tsx +17 -3
  46. package/src/components/Header/index.tsx +3 -0
  47. package/src/components/Header/styles.scss +1 -0
  48. package/src/components/HeaderControls/index.tsx +1 -0
  49. package/src/components/MainReport/index.tsx +3 -0
  50. package/src/components/Metadata/index.tsx +2 -0
  51. package/src/components/MetadataButton/index.tsx +35 -8
  52. package/src/components/MetadataButton/styles.scss +20 -0
  53. package/src/components/Modal/index.tsx +2 -0
  54. package/src/components/NavTabs/index.tsx +2 -1
  55. package/src/components/ReportBody/HeaderActions.tsx +1 -0
  56. package/src/components/ReportBody/SortBy.tsx +2 -0
  57. package/src/components/ReportBody/index.tsx +4 -1
  58. package/src/components/ReportCategories/index.tsx +2 -0
  59. package/src/components/ReportFilters/BaseFilters.tsx +2 -0
  60. package/src/components/ReportFilters/CategoriesFilter.tsx +2 -0
  61. package/src/components/ReportFilters/RetryFlaky.tsx +2 -0
  62. package/src/components/ReportFilters/TagsFilter.tsx +2 -0
  63. package/src/components/ReportFilters/TransitionFilter.tsx +2 -0
  64. package/src/components/ReportFilters/index.tsx +3 -0
  65. package/src/components/ReportGlobalAttachments/index.tsx +3 -0
  66. package/src/components/ReportGlobalErrors/index.tsx +2 -0
  67. package/src/components/ReportHeader/ReportHeaderLabelList.tsx +1 -0
  68. package/src/components/ReportHeader/ReportHeaderLogo.tsx +3 -1
  69. package/src/components/ReportHeader/ReportHeaderPie.tsx +2 -0
  70. package/src/components/ReportHeader/index.tsx +2 -0
  71. package/src/components/ReportMetadata/MetadataItem.tsx +1 -0
  72. package/src/components/ReportMetadata/MetadataSummary.tsx +3 -1
  73. package/src/components/ReportMetadata/MetadataTestType.tsx +2 -0
  74. package/src/components/ReportMetadata/MetadataWithIcon.tsx +2 -0
  75. package/src/components/ReportMetadata/index.tsx +61 -17
  76. package/src/components/ReportQualityGateResults/index.tsx +6 -2
  77. package/src/components/ReportSearch/index.tsx +1 -0
  78. package/src/components/ReportTabs/index.tsx +3 -0
  79. package/src/components/SectionPicker/index.tsx +2 -0
  80. package/src/components/SectionSwitcher/index.tsx +3 -0
  81. package/src/components/SideBySide/index.tsx +1 -0
  82. package/src/components/SplitLayout/index.tsx +2 -0
  83. package/src/components/TestResult/TestStepsEmpty/index.tsx +2 -0
  84. package/src/components/TestResult/TrAttachmentsView/index.tsx +2 -0
  85. package/src/components/TestResult/TrDescription/index.tsx +16 -3
  86. package/src/components/TestResult/TrDropdown/index.tsx +1 -0
  87. package/src/components/TestResult/TrEmpty/index.tsx +3 -1
  88. package/src/components/TestResult/TrEnvironmentItem/index.tsx +3 -0
  89. package/src/components/TestResult/TrEnvironmentsView/index.tsx +8 -2
  90. package/src/components/TestResult/TrError/TrDiff.tsx +3 -1
  91. package/src/components/TestResult/TrError/index.tsx +20 -18
  92. package/src/components/TestResult/TrError/styles.scss +0 -25
  93. package/src/components/TestResult/TrHeader/TrBreadcrumbs.tsx +3 -1
  94. package/src/components/TestResult/TrHeader/index.tsx +2 -0
  95. package/src/components/TestResult/TrHeader/styles.scss +1 -0
  96. package/src/components/TestResult/TrHistory/TrHistoryItem.tsx +3 -1
  97. package/src/components/TestResult/TrHistory/index.tsx +2 -0
  98. package/src/components/TestResult/TrInfo/TrInfoStatuses.tsx +2 -0
  99. package/src/components/TestResult/TrInfo/index.tsx +2 -0
  100. package/src/components/TestResult/TrLinks/index.tsx +63 -11
  101. package/src/components/TestResult/TrMetadata/index.tsx +44 -5
  102. package/src/components/TestResult/TrNavigation/index.tsx +2 -0
  103. package/src/components/TestResult/TrOverview.tsx +20 -17
  104. package/src/components/TestResult/TrParameters/index.tsx +41 -7
  105. package/src/components/TestResult/TrPrevStatuses/index.tsx +2 -0
  106. package/src/components/TestResult/TrPwTraces/PwTraceButton.tsx +44 -9
  107. package/src/components/TestResult/TrPwTraces/index.tsx +5 -1
  108. package/src/components/TestResult/TrPwTraces/openPwTraceInNewTab.ts +29 -0
  109. package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +3 -1
  110. package/src/components/TestResult/TrRetriesView/index.tsx +2 -0
  111. package/src/components/TestResult/TrSetup/index.tsx +3 -1
  112. package/src/components/TestResult/TrSeverity/index.tsx +2 -0
  113. package/src/components/TestResult/TrStatus/index.tsx +2 -0
  114. package/src/components/TestResult/TrSteps/TrAttachment.tsx +38 -6
  115. package/src/components/TestResult/TrSteps/TrAttachmentInfo.tsx +50 -2
  116. package/src/components/TestResult/TrSteps/TrBodyItems.tsx +42 -0
  117. package/src/components/TestResult/TrSteps/TrErrorStep.tsx +40 -0
  118. package/src/components/TestResult/TrSteps/TrStep.tsx +31 -65
  119. package/src/components/TestResult/TrSteps/TrStepHeader.tsx +50 -0
  120. package/src/components/TestResult/TrSteps/TrStepInfo.tsx +1 -0
  121. package/src/components/TestResult/TrSteps/index.tsx +12 -32
  122. package/src/components/TestResult/TrSteps/styles.scss +8 -0
  123. package/src/components/TestResult/TrSteps/wrongAttachment.tsx +2 -1
  124. package/src/components/TestResult/TrTabs/index.tsx +1 -0
  125. package/src/components/TestResult/TrTeardown/index.tsx +3 -1
  126. package/src/components/TestResult/bodyItems.ts +151 -0
  127. package/src/components/TestResult/index.tsx +2 -0
  128. package/src/components/Timeline/index.tsx +12 -2
  129. package/src/components/ToggleLayout/index.tsx +1 -0
  130. package/src/components/Tree/index.tsx +6 -2
  131. package/src/components/Tree/styles.scss +11 -0
  132. package/src/index.tsx +9 -3
  133. package/src/locales/ar.json +427 -0
  134. package/src/locales/az.json +43 -46
  135. package/src/locales/de.json +5 -0
  136. package/src/locales/en.json +5 -0
  137. package/src/locales/es.json +5 -0
  138. package/src/locales/fr.json +5 -0
  139. package/src/locales/he.json +5 -0
  140. package/src/locales/hy.json +5 -0
  141. package/src/locales/it.json +5 -0
  142. package/src/locales/ja.json +5 -0
  143. package/src/locales/ka.json +5 -0
  144. package/src/locales/kr.json +5 -0
  145. package/src/locales/nl.json +5 -0
  146. package/src/locales/pl.json +5 -0
  147. package/src/locales/pt.json +5 -0
  148. package/src/locales/ru.json +5 -0
  149. package/src/locales/sv.json +5 -0
  150. package/src/locales/tr.json +5 -0
  151. package/src/locales/uk.json +5 -0
  152. package/src/locales/zh-TW.json +432 -0
  153. package/src/locales/zh.json +5 -0
  154. package/src/stores/categories.ts +1 -0
  155. package/src/stores/chart.ts +2 -1
  156. package/src/stores/env.ts +14 -4
  157. package/src/stores/envInfo.ts +1 -0
  158. package/src/stores/globals.ts +1 -0
  159. package/src/stores/locale.ts +1 -0
  160. package/src/stores/qualityGate.ts +1 -0
  161. package/src/stores/sections.ts +1 -0
  162. package/src/stores/stats.ts +12 -6
  163. package/src/stores/testResult.ts +1 -0
  164. package/src/stores/testResults.ts +1 -0
  165. package/src/stores/timeline.ts +2 -0
  166. package/src/stores/tree.ts +2 -0
  167. package/src/stores/treeFilters/actions.ts +1 -0
  168. package/src/stores/treeFilters/store.ts +1 -0
  169. package/src/stores/treeFilters/utils.ts +1 -0
  170. package/src/stores/variables.ts +1 -0
  171. package/src/utils/time.ts +1 -0
  172. package/src/utils/treeFilters.ts +2 -0
  173. package/test/components/EnvironmentPicker.test.tsx +133 -0
  174. package/test/components/Header/CiInfo.test.tsx +15 -0
  175. package/test/components/Header.test.tsx +1 -0
  176. package/test/components/TestResult/PwTraceButton.test.tsx +104 -0
  177. package/test/components/TestResult/TrErrorStep.test.tsx +127 -0
  178. package/test/components/TestResult/TrOverview.test.tsx +114 -0
  179. package/test/components/TestResult/bodyItems.test.ts +194 -0
  180. package/test/components/TestResult/openPwTraceInNewTab.test.ts +65 -0
  181. package/test/components/Timeline.test.tsx +104 -0
  182. package/test/stores/treeFilters/actions.test.ts +82 -0
  183. package/test/utils/ownerAddress.test.ts +1 -0
  184. package/test/utils/treeFilters.test.ts +1 -0
  185. package/tsconfig.json +1 -2
  186. package/tsconfig.node.json +2 -1
  187. package/types.d.ts +2 -0
  188. package/.eslintrc.cjs +0 -18
  189. package/dist/multi/173.app-8be6acc0a596a2197dbf.js +0 -1
  190. package/dist/multi/174.app-8be6acc0a596a2197dbf.js +0 -1
  191. package/dist/multi/252.app-8be6acc0a596a2197dbf.js +0 -1
  192. package/dist/multi/282.app-8be6acc0a596a2197dbf.js +0 -1
  193. package/dist/multi/29.app-8be6acc0a596a2197dbf.js +0 -1
  194. package/dist/multi/416.app-8be6acc0a596a2197dbf.js +0 -1
  195. package/dist/multi/527.app-8be6acc0a596a2197dbf.js +0 -1
  196. package/dist/multi/600.app-8be6acc0a596a2197dbf.js +0 -1
  197. package/dist/multi/605.app-8be6acc0a596a2197dbf.js +0 -1
  198. package/dist/multi/638.app-8be6acc0a596a2197dbf.js +0 -1
  199. package/dist/multi/672.app-8be6acc0a596a2197dbf.js +0 -1
  200. package/dist/multi/686.app-8be6acc0a596a2197dbf.js +0 -1
  201. package/dist/multi/725.app-8be6acc0a596a2197dbf.js +0 -1
  202. package/dist/multi/741.app-8be6acc0a596a2197dbf.js +0 -1
  203. package/dist/multi/749.app-8be6acc0a596a2197dbf.js +0 -1
  204. package/dist/multi/755.app-8be6acc0a596a2197dbf.js +0 -1
  205. package/dist/multi/943.app-8be6acc0a596a2197dbf.js +0 -1
  206. package/dist/multi/980.app-8be6acc0a596a2197dbf.js +0 -1
  207. package/dist/multi/app-8be6acc0a596a2197dbf.js +0 -2
  208. package/dist/single/app-8221eb856e47b4ef50d6.js +0 -2
  209. package/src/components/TestResult/TrPwTraces/PwTrace.tsx +0 -34
@@ -1,20 +1,55 @@
1
1
  import type { AttachmentTestStepResult } from "@allurereport/core-api";
2
2
  import { fetchFromUrl } from "@allurereport/web-commons";
3
- import { IconButton, TooltipWrapper, allureIcons } from "@allurereport/web-components";
4
- import { PwTrace } from "@/components/TestResult/TrPwTraces/PwTrace";
3
+ import { Button, IconButton, Text, TooltipWrapper, allureIcons } from "@allurereport/web-components";
4
+
5
+ import { openPlaywrightTraceInNewTab } from "@/components/TestResult/TrPwTraces/openPwTraceInNewTab";
5
6
  import { useI18n } from "@/stores";
6
- import { openModal } from "@/stores/modal";
7
+ import { closeModal, openModal } from "@/stores/modal";
8
+
9
+ const PwTracePopupBlocked = ({ onRetry, t }: { onRetry: () => void; t: (key: string) => string }) => (
10
+ <div data-testid={"pw-trace-popup-blocked"}>
11
+ <Text>
12
+ {t("pwTracePopupBlocked")}
13
+ <br />
14
+ {t("pwTracePopupBlockedHint")}
15
+ </Text>
16
+ <Button
17
+ style={"flat"}
18
+ size={"s"}
19
+ text={t("retries")}
20
+ onClick={() => {
21
+ closeModal();
22
+ onRetry();
23
+ }}
24
+ />
25
+ </div>
26
+ );
7
27
 
8
28
  export const PwTraceButton = ({ link }: Pick<AttachmentTestStepResult, "link">) => {
9
29
  const { t } = useI18n("ui");
30
+ const traceTitle = `Playwright Trace Viewer | ${link.name}${link.ext}`;
31
+
10
32
  const openPw = async () => {
11
- const hasPw = await fetchFromUrl(link);
12
- const blob = await hasPw.blob();
33
+ // Use a top-level tab for Playwright Trace to avoid third-party blob/storage partitioning issues.
34
+ // - https://bugzilla.mozilla.org/show_bug.cgi?id=1917842
35
+ // - https://privacysandbox.google.com/cookies/storage-partitioning
36
+ try {
37
+ const hasPw = await fetchFromUrl(link);
38
+ const blob = await hasPw.blob();
39
+ const opened = openPlaywrightTraceInNewTab(blob);
13
40
 
14
- openModal({
15
- component: <PwTrace blob={blob} />,
16
- title: `Playwright Trace Viewer | ${link.name}${link.ext}`,
17
- });
41
+ if (!opened) {
42
+ openModal({
43
+ title: traceTitle,
44
+ component: <PwTracePopupBlocked onRetry={openPw} t={t} />,
45
+ });
46
+ }
47
+ } catch {
48
+ openModal({
49
+ title: traceTitle,
50
+ component: <Text>Failed to load Playwright trace attachment.</Text>,
51
+ });
52
+ }
18
53
  };
19
54
 
20
55
  return (
@@ -2,8 +2,10 @@ import type { AttachmentTestStepResult } from "@allurereport/core-api";
2
2
  import type { FunctionalComponent } from "preact";
3
3
  import { useState } from "preact/hooks";
4
4
  import type { AwesomeTestResult } from "types";
5
+
5
6
  import { MetadataButton } from "@/components/MetadataButton";
6
7
  import { TrAttachment } from "@/components/TestResult/TrSteps/TrAttachment";
8
+
7
9
  import * as styles from "./styles.scss";
8
10
 
9
11
  export type TrMetadataProps = {
@@ -24,7 +26,9 @@ export const TrPwTraces: FunctionalComponent<TrMetadataProps> = ({ pwTraces }) =
24
26
  />
25
27
  {isOpened && (
26
28
  <div className={styles["tr-metadata-wrapper"]}>
27
- {pwTraces?.map((pw, index) => <TrAttachment stepIndex={index + 1} item={pw} key={pw.link.id} />)}
29
+ {pwTraces?.map((pw, index) => (
30
+ <TrAttachment stepIndex={index + 1} item={pw} key={pw.link.id} />
31
+ ))}
28
32
  </div>
29
33
  )}
30
34
  </div>
@@ -0,0 +1,29 @@
1
+ const PLAYWRIGHT_TRACE_ORIGIN = "https://trace.playwright.dev";
2
+ const PLAYWRIGHT_TRACE_URL = `${PLAYWRIGHT_TRACE_ORIGIN}/next/`;
3
+ const RETRY_DELAY_MS = 300;
4
+
5
+ export const openPlaywrightTraceInNewTab = (blob: Blob) => {
6
+ const newWindow = window.open("", "_blank");
7
+ if (!newWindow) {
8
+ return false;
9
+ }
10
+
11
+ const payload = { method: "load", params: { trace: blob } };
12
+ const sendTraceMessage = () => {
13
+ if (newWindow.closed) {
14
+ return;
15
+ }
16
+
17
+ newWindow.postMessage(payload, PLAYWRIGHT_TRACE_ORIGIN);
18
+ };
19
+
20
+ newWindow.location.href = PLAYWRIGHT_TRACE_URL;
21
+ newWindow.focus();
22
+
23
+ sendTraceMessage();
24
+ globalThis.setTimeout(() => {
25
+ sendTraceMessage();
26
+ }, RETRY_DELAY_MS);
27
+
28
+ return true;
29
+ };
@@ -3,12 +3,14 @@ import { ArrowButton, IconButton, Text, TreeItemIcon, allureIcons } from "@allur
3
3
  import type { FunctionalComponent } from "preact";
4
4
  import { useState } from "preact/hooks";
5
5
  import type { AwesomeTestResult } from "types";
6
+
6
7
  import { TrError } from "@/components/TestResult/TrError";
7
- import * as styles from "@/components/TestResult/TrRetriesView/styles.scss";
8
8
  import { useI18n } from "@/stores/locale";
9
9
  import { navigateToTestResult } from "@/stores/router";
10
10
  import { timestampToDate } from "@/utils/time";
11
11
 
12
+ import * as styles from "@/components/TestResult/TrRetriesView/styles.scss";
13
+
12
14
  export type TrRetriesItemProps = {
13
15
  testResultItem: AwesomeTestResult;
14
16
  attempt: number;
@@ -1,8 +1,10 @@
1
1
  import { EmptyView } from "@allurereport/web-components";
2
2
  import type { FunctionalComponent } from "preact";
3
3
  import type { AwesomeTestResult } from "types";
4
+
4
5
  import { TrRetriesItem } from "@/components/TestResult/TrRetriesView/TrRetriesItem";
5
6
  import { useI18n } from "@/stores";
7
+
6
8
  import * as styles from "./styles.scss";
7
9
 
8
10
  export const TrRetriesView: FunctionalComponent<{
@@ -2,13 +2,15 @@ import { allureIcons } from "@allurereport/web-components";
2
2
  import type { FunctionalComponent } from "preact";
3
3
  import { useState } from "preact/hooks";
4
4
  import type { AwesomeTestResult } from "types";
5
+
5
6
  import { TrDropdown } from "@/components/TestResult/TrDropdown";
6
7
  import { TrAttachment } from "@/components/TestResult/TrSteps/TrAttachment";
7
8
  import { TrStep } from "@/components/TestResult/TrSteps/TrStep";
8
- import * as styles from "@/components/TestResult/TrSteps/styles.scss";
9
9
  import { useI18n } from "@/stores/locale";
10
10
  import { collapsedTrees, toggleTree } from "@/stores/tree";
11
11
 
12
+ import * as styles from "@/components/TestResult/TrSteps/styles.scss";
13
+
12
14
  const typeMap = {
13
15
  before: TrStep,
14
16
  after: TrStep,
@@ -1,7 +1,9 @@
1
1
  import { capitalize } from "@allurereport/core-api";
2
2
  import { SvgIcon, Text, allureIcons } from "@allurereport/web-components";
3
3
  import clsx from "clsx";
4
+
4
5
  import { useI18n } from "@/stores/locale";
6
+
5
7
  import * as styles from "./styles.scss";
6
8
 
7
9
  const icons: Record<string, string> = {
@@ -2,7 +2,9 @@ import type { TestStatus } from "@allurereport/core-api";
2
2
  import { capitalize } from "@allurereport/core-api";
3
3
  import { Text, TreeItemIcon } from "@allurereport/web-components";
4
4
  import clsx from "clsx";
5
+
5
6
  import { useI18n } from "@/stores";
7
+
6
8
  import * as styles from "./styles.scss";
7
9
 
8
10
  export const TrStatus = ({ status }: { status: TestStatus }) => {
@@ -1,13 +1,16 @@
1
1
  import type { AttachmentTestStepResult } from "@allurereport/core-api";
2
- import { attachmentType } from "@allurereport/web-commons";
2
+ import { attachmentType, isPreviewableContentType, 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";
6
6
  import { useState } from "preact/hooks";
7
+
7
8
  import { TrAttachmentInfo } from "@/components/TestResult/TrSteps/TrAttachmentInfo";
8
- import * as styles from "@/components/TestResult/TrSteps/styles.scss";
9
9
  import { useI18n } from "@/stores";
10
10
  import { openModal } from "@/stores/modal";
11
+ import { collapsedTrees, toggleTree } from "@/stores/tree";
12
+
13
+ import * as styles from "@/components/TestResult/TrSteps/styles.scss";
11
14
 
12
15
  const { lineImagesImage, lineFilesFileAttachment2, playwrightLogo } = allureIcons;
13
16
 
@@ -51,17 +54,30 @@ const iconMap: Record<string, string> = {
51
54
  "application/vnd.allure.playwright-trace": playwrightLogo,
52
55
  };
53
56
 
57
+ const HAS_PREVIEW_COMPONENT = new Set(["html"]);
58
+
54
59
  export const TrAttachment: FunctionComponent<{
55
60
  item: AttachmentTestStepResult;
56
61
  stepIndex?: number;
57
62
  className?: string;
58
63
  }> = ({ item, stepIndex }) => {
59
- const [isOpened, setIsOpen] = useState(false);
64
+ const attachmentTreeId = item.link?.id !== null ? `attachment-${item.link.id}` : null;
65
+ const isOpened = !collapsedTrees.value.has(attachmentTreeId);
66
+ const [showPreview, setShowPreview] = useState(false);
67
+ const [highlightCode, setHighlightCode] = useState(true);
60
68
  const { t: tAttachments } = useI18n("attachments");
61
69
  const { link } = item;
62
70
  const { missed } = link;
63
71
  const componentType = attachmentType(link.contentType);
64
72
  const isValidComponentType = !["archive", null].includes(componentType);
73
+ const isPreviewable = HAS_PREVIEW_COMPONENT.has(componentType ?? "");
74
+ const isCodeView = (componentType === "code" || componentType === "text") && (!isPreviewable || !showPreview);
75
+ const isSyntaxHighlightable = isSyntaxHighlightSupported({
76
+ contentType: link.contentType,
77
+ ext: link.ext,
78
+ name: link.name,
79
+ originalFileName: link.originalFileName,
80
+ });
65
81
 
66
82
  const expandAttachment = (event: Event) => {
67
83
  event.stopPropagation();
@@ -83,7 +99,9 @@ export const TrAttachment: FunctionComponent<{
83
99
  })}
84
100
  onClick={(e) => {
85
101
  e.stopPropagation();
86
- setIsOpen((prev) => !prev);
102
+ if (attachmentTreeId !== null) {
103
+ toggleTree(attachmentTreeId);
104
+ }
87
105
  }}
88
106
  >
89
107
  {isValidComponentType ? <ArrowButton isOpened={isOpened} /> : <div className={styles["test-result-strut"]} />}
@@ -105,13 +123,27 @@ export const TrAttachment: FunctionComponent<{
105
123
  </Text>
106
124
  )}
107
125
  <div>
108
- <TrAttachmentInfo item={item} shouldExpand={isValidComponentType} />
126
+ <TrAttachmentInfo
127
+ item={item}
128
+ shouldExpand={isValidComponentType}
129
+ isPreviewable={isPreviewable}
130
+ showPreview={showPreview}
131
+ onPreviewToggle={isPreviewable ? () => setShowPreview((p) => !p) : undefined}
132
+ isCodeView={isCodeView && isSyntaxHighlightable}
133
+ highlightCode={highlightCode}
134
+ onHighlightToggle={isCodeView && isSyntaxHighlightable ? () => setHighlightCode((h) => !h) : undefined}
135
+ />
109
136
  </div>
110
137
  </div>
111
138
  {isOpened && isValidComponentType && (
112
139
  <div className={styles["test-result-attachment-content-wrapper"]}>
113
140
  <div className={styles["test-result-attachment-content"]} role={"button"} onClick={expandAttachment}>
114
- <Attachment item={item} i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }} />
141
+ <Attachment
142
+ item={item}
143
+ previewable={showPreview}
144
+ highlightCode={highlightCode}
145
+ i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }}
146
+ />
115
147
  </div>
116
148
  </div>
117
149
  )}
@@ -1,20 +1,38 @@
1
1
  import type { AttachmentTestStepResult } from "@allurereport/core-api";
2
2
  import { downloadAttachment } from "@allurereport/web-commons";
3
3
  import { Attachment, IconButton, Text, TooltipWrapper, allureIcons } from "@allurereport/web-components";
4
+ import cx from "clsx";
4
5
  import { filesize } from "filesize";
5
6
  import type { FunctionalComponent } from "preact";
6
7
  import { useEffect } from "preact/hooks";
8
+
7
9
  import { PwTraceButton } from "@/components/TestResult/TrPwTraces/PwTraceButton";
8
- import * as styles from "@/components/TestResult/TrSteps/styles.scss";
9
10
  import { useI18n } from "@/stores";
10
11
  import { isModalOpen, openModal } from "@/stores/modal";
11
12
 
13
+ import * as styles from "@/components/TestResult/TrSteps/styles.scss";
14
+
12
15
  interface TrAttachmentInfo {
13
16
  item?: AttachmentTestStepResult;
14
17
  shouldExpand?: boolean;
18
+ isPreviewable?: boolean;
19
+ showPreview?: boolean;
20
+ onPreviewToggle?: () => void;
21
+ isCodeView?: boolean;
22
+ highlightCode?: boolean;
23
+ onHighlightToggle?: () => void;
15
24
  }
16
25
 
17
- export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({ item, shouldExpand }) => {
26
+ export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({
27
+ item,
28
+ shouldExpand,
29
+ isPreviewable,
30
+ showPreview,
31
+ onPreviewToggle,
32
+ isCodeView,
33
+ highlightCode = true,
34
+ onHighlightToggle,
35
+ }) => {
18
36
  const { t: tooltip } = useI18n("controls");
19
37
  const { t: tAttachments } = useI18n("attachments");
20
38
  const { id, ext, contentType } = item.link;
@@ -62,6 +80,36 @@ export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({ item,
62
80
  {Boolean(contentSize) && <Text size={"s"}>{contentSize}</Text>}
63
81
  <div className={styles["item-buttons"]}>
64
82
  {isPwTrace && <PwTraceButton link={item.link} />}
83
+ {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>
97
+ )}
98
+ {isCodeView && onHighlightToggle && (
99
+ <TooltipWrapper tooltipText={tooltip("syntaxHighlight")}>
100
+ <IconButton
101
+ className={cx(styles["item-button"], !highlightCode && styles["item-button-syntax-off"])}
102
+ style={"ghost"}
103
+ size={"s"}
104
+ iconSize={"s"}
105
+ icon={allureIcons.lineDevCodeSquare}
106
+ onClick={(e: Event) => {
107
+ e.stopPropagation();
108
+ onHighlightToggle();
109
+ }}
110
+ />
111
+ </TooltipWrapper>
112
+ )}
65
113
  {shouldExpand && (
66
114
  <TooltipWrapper tooltipText={tooltip("expand")}>
67
115
  <IconButton
@@ -0,0 +1,42 @@
1
+ import type { FunctionalComponent } from "preact";
2
+
3
+ import type { TrBodyItem } from "@/components/TestResult/bodyItems";
4
+ import { TrAttachment } from "@/components/TestResult/TrSteps/TrAttachment";
5
+ import { TrErrorStep } from "@/components/TestResult/TrSteps/TrErrorStep";
6
+ import { TrStep } from "@/components/TestResult/TrSteps/TrStep";
7
+
8
+ const getBodyItemKey = (item: TrBodyItem, index: number) => {
9
+ switch (item.type) {
10
+ case "step":
11
+ return item.item.stepId ?? `${item.item.name}-${index}`;
12
+ case "attachment":
13
+ return item.link.id;
14
+ case "error":
15
+ return item.id;
16
+ default:
17
+ return `${index}`;
18
+ }
19
+ };
20
+
21
+ export type TrBodyItemsProps = {
22
+ bodyItems: TrBodyItem[];
23
+ };
24
+
25
+ export const TrBodyItems: FunctionalComponent<TrBodyItemsProps> = ({ bodyItems }) => {
26
+ return (
27
+ <>
28
+ {bodyItems.map((item, index) => {
29
+ switch (item.type) {
30
+ case "step":
31
+ return <TrStep item={item} stepIndex={index + 1} key={getBodyItemKey(item, index)} />;
32
+ case "attachment":
33
+ return <TrAttachment item={item} stepIndex={index + 1} key={getBodyItemKey(item, index)} />;
34
+ case "error":
35
+ return <TrErrorStep item={item} stepIndex={index + 1} key={getBodyItemKey(item, index)} />;
36
+ default:
37
+ return null;
38
+ }
39
+ })}
40
+ </>
41
+ );
42
+ };
@@ -0,0 +1,40 @@
1
+ import clsx from "clsx";
2
+ import type { FunctionComponent } from "preact";
3
+
4
+ import { hasTestLevelErrorContent, type TestLevelErrorItem } from "@/components/TestResult/bodyItems";
5
+ import { TrError } from "@/components/TestResult/TrError";
6
+ import { TrStepHeader } from "@/components/TestResult/TrSteps/TrStepHeader";
7
+ import { collapsedTrees, toggleTree } from "@/stores/tree";
8
+
9
+ import * as styles from "@/components/TestResult/TrSteps/styles.scss";
10
+
11
+ export type TrErrorStepProps = {
12
+ item: TestLevelErrorItem;
13
+ stepIndex?: number;
14
+ };
15
+
16
+ export const TrErrorStep: FunctionComponent<TrErrorStepProps> = ({ item, stepIndex }) => {
17
+ const isOpened = !collapsedTrees.value.has(item.id);
18
+ const hasContent = hasTestLevelErrorContent(item.error);
19
+
20
+ return (
21
+ <div data-testid="test-result-step" className={styles["test-result-step"]}>
22
+ <TrStepHeader
23
+ title={item.title}
24
+ status={item.status}
25
+ stepIndex={stepIndex}
26
+ isOpened={isOpened}
27
+ hasContent={hasContent}
28
+ onToggle={() => toggleTree(item.id)}
29
+ />
30
+ {isOpened && hasContent && (
31
+ <div
32
+ data-testid="test-result-step-content"
33
+ className={clsx(styles["test-result-step-content"], styles["test-result-error-step-content"])}
34
+ >
35
+ <TrError {...item.error} status={item.status} showMessage={false} />
36
+ </div>
37
+ )}
38
+ </div>
39
+ );
40
+ };
@@ -1,16 +1,17 @@
1
- import type { DefaultTestStepResult, TestStepResult } from "@allurereport/core-api";
2
- import { ArrowButton, Code, Text, TreeItemIcon, allureIcons } from "@allurereport/web-components";
3
1
  import type { FunctionComponent } from "preact";
4
- import { useState } from "preact/hooks";
2
+
5
3
  import { MetadataList } from "@/components/Metadata";
6
4
  import { type MetadataItem } from "@/components/ReportMetadata";
5
+ import type { TrStepItem } from "@/components/TestResult/bodyItems";
7
6
  import { TrError } from "@/components/TestResult/TrError";
8
- import { TrAttachment } from "@/components/TestResult/TrSteps/TrAttachment";
7
+ import { TrBodyItems } from "@/components/TestResult/TrSteps/TrBodyItems";
8
+ import { TrStepHeader } from "@/components/TestResult/TrSteps/TrStepHeader";
9
9
  import { TrStepInfo } from "@/components/TestResult/TrSteps/TrStepInfo";
10
- import * as styles from "@/components/TestResult/TrSteps/styles.scss";
11
10
  import { collapsedTrees, toggleTree } from "@/stores/tree";
12
11
 
13
- export const TrStepParameters = (props: { parameters: DefaultTestStepResult["parameters"] }) => {
12
+ import * as styles from "@/components/TestResult/TrSteps/styles.scss";
13
+
14
+ export const TrStepParameters = (props: { parameters: TrStepItem["item"]["parameters"] }) => {
14
15
  const { parameters } = props;
15
16
 
16
17
  return (
@@ -20,78 +21,43 @@ export const TrStepParameters = (props: { parameters: DefaultTestStepResult["par
20
21
  );
21
22
  };
22
23
 
23
- export const TrStepsContent = (props: { item: DefaultTestStepResult }) => {
24
- const { item } = props;
24
+ export const TrStepsContent = (props: { item: TrStepItem }) => {
25
+ const { item: stepData, bodyItems, suppressInlineError } = props.item;
26
+ const hasInlineError = Boolean(
27
+ (stepData.message || stepData.trace) && !stepData.hasSimilarErrorInSubSteps && !suppressInlineError,
28
+ );
25
29
 
26
30
  return (
27
31
  <div data-testid={"test-result-step-content"} className={styles["test-result-step-content"]}>
28
- {Boolean(item?.parameters?.length) && <TrStepParameters parameters={item.parameters} />}
29
- {Boolean((item?.message || item?.trace) && !item?.hasSimilarErrorInSubSteps) && <TrError {...item} />}
30
- {Boolean(item?.steps?.length) && (
31
- <>
32
- {item.steps?.map((subItem, key) => {
33
- if (subItem.type === "step") {
34
- return <TrStep stepIndex={key + 1} key={key} item={subItem} />;
35
- }
36
-
37
- if (subItem.type === "attachment") {
38
- return <TrAttachment stepIndex={key + 1} key={key} item={subItem} />;
39
- }
40
-
41
- return null;
42
- })}
43
- </>
44
- )}
32
+ {Boolean(stepData.parameters?.length) && <TrStepParameters parameters={stepData.parameters} />}
33
+ {hasInlineError && <TrError {...stepData} />}
34
+ {Boolean(bodyItems.length) && <TrBodyItems bodyItems={bodyItems} />}
45
35
  </div>
46
36
  );
47
37
  };
48
38
 
49
- const hasFailedStep = (step: TestStepResult): boolean => {
50
- if (step.type !== "step") {
51
- return false;
52
- }
53
-
54
- return step.status !== "passed" || step.steps.some(hasFailedStep);
55
- };
56
-
57
39
  export const TrStep: FunctionComponent<{
58
- item: DefaultTestStepResult;
40
+ item: TrStepItem;
59
41
  stepIndex?: number;
60
- className?: string;
61
42
  }> = ({ item, stepIndex }) => {
62
- const haveFailedSteps = hasFailedStep(item);
63
- const isEarlyOpened = collapsedTrees.value.has(item.stepId) ? false : Boolean(haveFailedSteps);
64
- const [isOpened, setIsOpen] = useState(isEarlyOpened || false);
65
- const hasContent = Boolean(item?.steps?.length || item?.parameters?.length || item?.message || item?.trace);
66
-
67
- const handleClick = () => {
68
- setIsOpen(!isOpened);
69
- toggleTree(item.stepId);
70
- };
43
+ const { item: stepData, bodyItems, suppressInlineError } = item;
44
+ const hasInlineError = Boolean(
45
+ (stepData.message || stepData.trace) && !stepData.hasSimilarErrorInSubSteps && !suppressInlineError,
46
+ );
47
+ const hasContent = Boolean(bodyItems.length || stepData.parameters?.length || hasInlineError);
48
+ const isOpened = !collapsedTrees.value.has(stepData.stepId);
71
49
 
72
50
  return (
73
51
  <div data-testid={"test-result-step"} className={styles["test-result-step"]}>
74
- <div className={styles["test-result-step-header"]} onClick={handleClick}>
75
- {!hasContent ? (
76
- <div className={styles["test-result-strut"]} />
77
- ) : (
78
- <ArrowButton
79
- isOpened={isOpened}
80
- icon={allureIcons.arrowsChevronDown}
81
- iconSize={"xs"}
82
- className={!hasContent ? styles["test-result-visibility-hidden"] : ""}
83
- data-testid={"test-result-step-arrow-button"}
84
- />
85
- )}
86
- <TreeItemIcon status={item.status} />
87
- <Code size={"s"} className={styles["test-result-step-number"]}>
88
- {stepIndex}
89
- </Code>
90
- <Text data-testid={"test-result-step-title"} className={styles["test-result-header-text"]}>
91
- {item.name}
92
- </Text>
93
- <TrStepInfo item={item} />
94
- </div>
52
+ <TrStepHeader
53
+ title={stepData.name}
54
+ status={stepData.status}
55
+ stepIndex={stepIndex}
56
+ isOpened={isOpened}
57
+ hasContent={hasContent}
58
+ onToggle={() => toggleTree(stepData.stepId)}
59
+ extra={<TrStepInfo item={stepData} />}
60
+ />
95
61
  {hasContent && isOpened && <TrStepsContent item={item} />}
96
62
  </div>
97
63
  );
@@ -0,0 +1,50 @@
1
+ import type { TestStatus } from "@allurereport/core-api";
2
+ import { ArrowButton, Code, Text, TreeItemIcon, allureIcons } from "@allurereport/web-components";
3
+ import type { FunctionComponent } from "preact";
4
+
5
+ import * as styles from "@/components/TestResult/TrSteps/styles.scss";
6
+
7
+ export type TrStepHeaderProps = {
8
+ title: string;
9
+ status: TestStatus;
10
+ stepIndex?: number;
11
+ isOpened: boolean;
12
+ hasContent: boolean;
13
+ onToggle: () => void;
14
+ extra?: preact.ComponentChildren;
15
+ };
16
+
17
+ export const TrStepHeader: FunctionComponent<TrStepHeaderProps> = ({
18
+ title,
19
+ status,
20
+ stepIndex,
21
+ isOpened,
22
+ hasContent,
23
+ onToggle,
24
+ extra,
25
+ }) => (
26
+ <div
27
+ data-testid="test-result-step-header"
28
+ className={styles["test-result-step-header"]}
29
+ onClick={hasContent ? onToggle : undefined}
30
+ >
31
+ {!hasContent ? (
32
+ <div className={styles["test-result-strut"]} />
33
+ ) : (
34
+ <ArrowButton
35
+ isOpened={isOpened}
36
+ icon={allureIcons.arrowsChevronDown}
37
+ iconSize="xs"
38
+ data-testid="test-result-step-arrow-button"
39
+ />
40
+ )}
41
+ <TreeItemIcon status={status} />
42
+ <Code size="s" className={styles["test-result-step-number"]}>
43
+ {stepIndex}
44
+ </Code>
45
+ <Text data-testid="test-result-step-title" className={styles["test-result-header-text"]}>
46
+ {title}
47
+ </Text>
48
+ {extra}
49
+ </div>
50
+ );
@@ -6,6 +6,7 @@ import {
6
6
  } from "@allurereport/core-api";
7
7
  import { SvgIcon, Text, allureIcons } from "@allurereport/web-components";
8
8
  import clsx from "clsx";
9
+
9
10
  import * as styles from "@/components/TestResult/TrSteps/styles.scss";
10
11
 
11
12
  const countErrorStatuses = (step: TestStepResult): Record<string, number> => {