@allurereport/web-awesome 3.9.0 → 3.11.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.
- package/dist/multi/173.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/174.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/252.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/282.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/29.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/310.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/416.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/507.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/527.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/600.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/605.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/638.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/672.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/686.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/725.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/741.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/749.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/755.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/894.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/943.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/980.app-79d160f9989770266f96.js +1 -0
- package/dist/multi/app-79d160f9989770266f96.js +2 -0
- package/dist/multi/manifest.json +25 -25
- package/dist/multi/styles-b7f017f505b72e148e8b.css +58 -0
- package/dist/single/app-36af07268613f77d3ac5.js +2 -0
- package/dist/single/manifest.json +1 -1
- package/package.json +15 -20
- package/src/components/BaseLayout/styles.scss +3 -1
- package/src/components/Footer/FooterVersion.tsx +5 -10
- package/src/components/Footer/index.tsx +7 -1
- package/src/components/Footer/styles.scss +6 -0
- package/src/components/Header/CiInfo/index.tsx +17 -13
- package/src/components/HeaderControls/index.tsx +1 -3
- package/src/components/KeyboardShortcuts/styles.scss +5 -5
- package/src/components/MainReport/index.tsx +3 -9
- package/src/components/MainReport/styles.scss +1 -26
- package/src/components/Metadata/index.tsx +27 -6
- package/src/components/Metadata/styles.scss +12 -0
- package/src/components/ReportBody/index.tsx +3 -12
- package/src/components/ReportBody/styles.scss +0 -21
- package/src/components/ReportHeader/index.tsx +25 -13
- package/src/components/ReportMetadata/index.tsx +35 -4
- package/src/components/SideBySide/styles.scss +10 -0
- package/src/components/SplitLayout/index.tsx +2 -9
- package/src/components/SplitLayout/styles.scss +4 -7
- package/src/components/TestResult/TrOverview.tsx +9 -2
- package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +27 -1
- package/src/components/TestResult/TrRetriesView/styles.scss +17 -7
- package/src/components/TestResult/TrSetup/index.tsx +1 -1
- package/src/components/TestResult/TrSteps/TrAttachment.tsx +2 -1
- package/src/components/TestResult/TrSteps/TrAttachmentInfo.tsx +11 -3
- package/src/components/TestResult/TrSteps/TrBodyItems.tsx +5 -2
- package/src/components/TestResult/TrSteps/TrStep.tsx +6 -2
- package/src/components/TestResult/TrSteps/index.tsx +8 -5
- package/src/components/TestResult/TrTeardown/index.tsx +1 -1
- package/src/components/TestResult/index.tsx +2 -3
- package/src/components/TestResult/styles.scss +0 -5
- package/src/components/Tree/index.tsx +21 -1
- package/src/locales/ar.json +1 -0
- package/src/locales/az.json +1 -0
- package/src/locales/de.json +1 -0
- package/src/locales/en.json +1 -0
- package/src/locales/es.json +1 -0
- package/src/locales/fr.json +1 -0
- package/src/locales/he.json +1 -0
- package/src/locales/hy.json +1 -0
- package/src/locales/it.json +1 -0
- package/src/locales/ja.json +1 -0
- package/src/locales/ka.json +1 -0
- package/src/locales/kr.json +1 -0
- package/src/locales/nl.json +1 -0
- package/src/locales/pl.json +1 -0
- package/src/locales/pt.json +1 -0
- package/src/locales/ru.json +1 -0
- package/src/locales/sv.json +1 -0
- package/src/locales/tr.json +1 -0
- package/src/locales/uk.json +1 -0
- package/src/locales/zh-TW.json +1 -0
- package/src/locales/zh.json +1 -0
- package/src/stores/locale.ts +4 -2
- package/src/stores/treeSort.ts +7 -1
- package/src/styles/_pane-active.scss +2 -2
- package/src/utils/atSeparator.ts +4 -0
- package/src/utils/time.ts +2 -1
- package/src/utils/treeFilters.ts +15 -4
- package/test/components/Footer.test.tsx +26 -0
- package/test/components/Header/CiInfo.test.tsx +48 -0
- package/test/components/HeaderControls.test.tsx +28 -0
- package/test/components/ReportHeader.test.tsx +77 -0
- package/test/components/ReportMetadata.test.tsx +131 -0
- package/test/components/TestResult/TrRetriesItem.test.tsx +163 -0
- package/test/components/TestResult/TrSteps.test.tsx +45 -10
- package/test/stores/treeSort.test.ts +58 -0
- package/test/utils/time.test.ts +52 -0
- package/test/utils/treeFilters.test.ts +104 -0
- package/types.d.ts +22 -0
- package/webpack.config.js +9 -7
- package/dist/multi/173.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/174.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/252.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/282.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/29.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/310.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/416.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/507.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/527.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/600.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/605.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/638.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/672.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/686.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/725.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/741.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/749.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/755.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/894.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/943.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/980.app-d36b0855e3e7a53eeee9.js +0 -1
- package/dist/multi/app-d36b0855e3e7a53eeee9.js +0 -2
- package/dist/multi/styles-468416ffee9a9dea6cae.css +0 -58
- package/dist/single/app-62171f5f51b5954a787c.js +0 -2
- /package/dist/multi/{121.app-d36b0855e3e7a53eeee9.js → 121.app-79d160f9989770266f96.js} +0 -0
- /package/dist/multi/{779.app-d36b0855e3e7a53eeee9.js → 779.app-79d160f9989770266f96.js} +0 -0
- /package/dist/multi/{app-d36b0855e3e7a53eeee9.js.LICENSE.txt → app-79d160f9989770266f96.js.LICENSE.txt} +0 -0
- /package/dist/single/{app-62171f5f51b5954a787c.js.LICENSE.txt → app-36af07268613f77d3ac5.js.LICENSE.txt} +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { EnvironmentItem } from "@allurereport/core-api";
|
|
2
|
+
import { getReportOptions } from "@allurereport/web-commons";
|
|
2
3
|
import { Button, Loadable } from "@allurereport/web-components";
|
|
3
4
|
import type { FunctionalComponent } from "preact";
|
|
4
5
|
import { useEffect } from "preact/hooks";
|
|
6
|
+
import type { AwesomeExecutorInfo, AwesomeReportOptions } from "types";
|
|
5
7
|
|
|
6
8
|
import { MetadataList } from "@/components/Metadata";
|
|
7
9
|
import { MetadataButton } from "@/components/MetadataButton";
|
|
@@ -19,6 +21,7 @@ const REPORT_VISIBLE_LIMIT = 8;
|
|
|
19
21
|
|
|
20
22
|
export interface MetadataItem extends EnvironmentItem {
|
|
21
23
|
value?: string;
|
|
24
|
+
url?: string;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
// TODO: check, where do we use the component and refactor it up to our needs
|
|
@@ -39,7 +42,7 @@ const Metadata: FunctionalComponent<MetadataProps> = ({ envInfo = [] }) => {
|
|
|
39
42
|
const showAllId = `${sectionId}-showAll`;
|
|
40
43
|
const isOpened = !collapsedTrees.value.has(sectionId);
|
|
41
44
|
const showAll = collapsedTrees.value.has(showAllId);
|
|
42
|
-
const list = envInfo.map((env) => ({ ...env, value: env.values.join(", ") }));
|
|
45
|
+
const list = envInfo.map((env) => ({ ...env, value: env.value ?? env.values.join(", ") }));
|
|
43
46
|
const totalCount = list.length;
|
|
44
47
|
const visibleList = totalCount <= REPORT_VISIBLE_LIMIT ? list : showAll ? list : list.slice(0, REPORT_VISIBLE_LIMIT);
|
|
45
48
|
const { t } = useI18n("ui");
|
|
@@ -109,8 +112,32 @@ const MetadataVariables: FunctionalComponent<MetadataVariablesProps> = (props) =
|
|
|
109
112
|
);
|
|
110
113
|
};
|
|
111
114
|
|
|
115
|
+
const getExecutorLabel = (executor?: AwesomeExecutorInfo) => {
|
|
116
|
+
if (!executor) return undefined;
|
|
117
|
+
if (executor.name && executor.buildName) return `${executor.name} · ${executor.buildName}`;
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
executor.buildName ||
|
|
121
|
+
executor.reportName ||
|
|
122
|
+
executor.name ||
|
|
123
|
+
executor.buildUrl ||
|
|
124
|
+
executor.reportUrl ||
|
|
125
|
+
executor.url
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const getExecutorMetadata = (executor?: AwesomeExecutorInfo): MetadataItem[] => {
|
|
130
|
+
const label = getExecutorLabel(executor);
|
|
131
|
+
|
|
132
|
+
return label
|
|
133
|
+
? [{ name: "executor", values: [], value: label, url: executor?.buildUrl || executor?.reportUrl || executor?.url }]
|
|
134
|
+
: [];
|
|
135
|
+
};
|
|
136
|
+
|
|
112
137
|
export const ReportMetadata = () => {
|
|
113
138
|
const envId = currentEnvironment.value;
|
|
139
|
+
const { executor } = getReportOptions<AwesomeReportOptions>();
|
|
140
|
+
const executorMetadata = getExecutorMetadata(executor);
|
|
114
141
|
const stats = envId ? statsByEnvStore.value.data[envId] : reportStatsStore.value.data;
|
|
115
142
|
|
|
116
143
|
useEffect(() => {
|
|
@@ -122,13 +149,17 @@ export const ReportMetadata = () => {
|
|
|
122
149
|
{stats && <MetadataSummary stats={stats} />}
|
|
123
150
|
<Loadable
|
|
124
151
|
source={variables}
|
|
125
|
-
transformData={(data) => data?.[
|
|
152
|
+
transformData={(data) => data?.[envId ?? "default"] ?? {}}
|
|
126
153
|
renderData={(data) => !!Object.keys(data).length && <MetadataVariables variables={data} />}
|
|
127
154
|
/>
|
|
128
155
|
<Loadable
|
|
129
156
|
source={envInfoStore}
|
|
130
|
-
renderError={() =>
|
|
131
|
-
renderData={(data) =>
|
|
157
|
+
renderError={() => Boolean(executorMetadata.length) && <Metadata envInfo={executorMetadata} />}
|
|
158
|
+
renderData={(data) => {
|
|
159
|
+
const metadata = [...executorMetadata, ...(data ?? [])];
|
|
160
|
+
|
|
161
|
+
return Boolean(metadata.length) && <Metadata envInfo={metadata} />;
|
|
162
|
+
}}
|
|
132
163
|
/>
|
|
133
164
|
</div>
|
|
134
165
|
);
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
box-shadow: var(--shadow-small);
|
|
23
23
|
overflow: hidden;
|
|
24
24
|
min-height: 0;
|
|
25
|
+
border-top: 2px solid transparent;
|
|
26
|
+
|
|
27
|
+
&[data-pane-active] {
|
|
28
|
+
border-top-color: var(--color-intent-primary-text);
|
|
29
|
+
}
|
|
25
30
|
|
|
26
31
|
> * {
|
|
27
32
|
flex: 1 1 auto;
|
|
@@ -35,6 +40,11 @@
|
|
|
35
40
|
border-radius: 0 12px 12px 0;
|
|
36
41
|
box-shadow: var(--shadow-small);
|
|
37
42
|
overflow: hidden;
|
|
43
|
+
border-top: 2px solid transparent;
|
|
44
|
+
|
|
45
|
+
&[data-pane-active] {
|
|
46
|
+
border-top-color: var(--color-intent-primary-text);
|
|
47
|
+
}
|
|
38
48
|
}
|
|
39
49
|
|
|
40
50
|
[dir="ltr"] {
|
|
@@ -8,7 +8,6 @@ import MainReport from "@/components/MainReport";
|
|
|
8
8
|
import SideBySide from "@/components/SideBySide";
|
|
9
9
|
import TestResult from "@/components/TestResult";
|
|
10
10
|
import { useI18n } from "@/stores";
|
|
11
|
-
import { activePane } from "@/stores/keyboard";
|
|
12
11
|
import { isSplitMode } from "@/stores/layout";
|
|
13
12
|
import { rootTabRoute, testResultRoute } from "@/stores/router";
|
|
14
13
|
import { currentTrId } from "@/stores/testResult";
|
|
@@ -21,7 +20,7 @@ const MainReportWrapper = () => {
|
|
|
21
20
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
22
21
|
|
|
23
22
|
return (
|
|
24
|
-
<div className={styles.wrapper} ref={containerRef}>
|
|
23
|
+
<div className={styles.wrapper} ref={containerRef} data-tree-scroll-container>
|
|
25
24
|
<MainReport />
|
|
26
25
|
</div>
|
|
27
26
|
);
|
|
@@ -62,13 +61,7 @@ export const SplitLayout = () => {
|
|
|
62
61
|
}}
|
|
63
62
|
/>
|
|
64
63
|
) : (
|
|
65
|
-
<div
|
|
66
|
-
className={clsx(
|
|
67
|
-
styles.empty,
|
|
68
|
-
isSplitMode.value && styles["empty-split-pane"],
|
|
69
|
-
isSplitMode.value && activePane.value === "testResult" && styles["pane-active"],
|
|
70
|
-
)}
|
|
71
|
-
>
|
|
64
|
+
<div className={clsx(styles.empty, isSplitMode.value && styles["empty-split-pane"])}>
|
|
72
65
|
<Text>{t("noSelectedTR")}</Text>
|
|
73
66
|
</div>
|
|
74
67
|
);
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
position: relative;
|
|
17
17
|
height: 100%;
|
|
18
18
|
min-height: 0;
|
|
19
|
+
overflow-y: auto;
|
|
20
|
+
overflow-x: hidden;
|
|
21
|
+
scrollbar-width: thin;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
.content {
|
|
@@ -85,14 +88,8 @@
|
|
|
85
88
|
|
|
86
89
|
.empty-split-pane {
|
|
87
90
|
position: relative;
|
|
88
|
-
background: var(--bg-
|
|
89
|
-
border-radius: 12px;
|
|
91
|
+
background: var(--color-bg-raised);
|
|
90
92
|
overflow: auto;
|
|
91
|
-
@include paneActive.split-pane-indicator;
|
|
92
|
-
|
|
93
|
-
&.pane-active {
|
|
94
|
-
@include paneActive.split-pane-indicator-active;
|
|
95
|
-
}
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
.header {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { FunctionalComponent } from "preact";
|
|
2
2
|
import type { AwesomeTestResult } from "types";
|
|
3
3
|
|
|
4
|
-
import { getBodyItems } from "@/components/TestResult/bodyItems";
|
|
4
|
+
import { getBodyItems, isDisplayableTestError } from "@/components/TestResult/bodyItems";
|
|
5
5
|
import TestStepsEmpty from "@/components/TestResult/TestStepsEmpty";
|
|
6
6
|
import { TrDescription } from "@/components/TestResult/TrDescription";
|
|
7
|
+
import { TrError } from "@/components/TestResult/TrError";
|
|
7
8
|
import { TrLinks } from "@/components/TestResult/TrLinks";
|
|
8
9
|
import { TrMetadata } from "@/components/TestResult/TrMetadata";
|
|
9
10
|
import { TrParameters } from "@/components/TestResult/TrParameters";
|
|
@@ -23,7 +24,7 @@ export type TrOverviewProps = {
|
|
|
23
24
|
|
|
24
25
|
export const TrOverview: FunctionalComponent<TrOverviewProps> = ({ testResult }) => {
|
|
25
26
|
useTestResultOverviewFocusScroll();
|
|
26
|
-
const { parameters, groupedLabels, links, descriptionHtml, setup, teardown, id } = testResult || {};
|
|
27
|
+
const { parameters, groupedLabels, links, descriptionHtml, setup, teardown, id, error, status } = testResult || {};
|
|
27
28
|
const testResultId = id ?? currentTrId.value;
|
|
28
29
|
const { t } = useI18n("ui");
|
|
29
30
|
const bodyItems = getBodyItems(testResult, t("error"));
|
|
@@ -31,9 +32,15 @@ export const TrOverview: FunctionalComponent<TrOverviewProps> = ({ testResult })
|
|
|
31
32
|
const pwTraces = testResult?.attachments?.filter(
|
|
32
33
|
(attachment) => attachment.link.contentType === "application/vnd.allure.playwright-trace",
|
|
33
34
|
);
|
|
35
|
+
const showTopError = (status === "failed" || status === "broken") && isDisplayableTestError(error);
|
|
34
36
|
|
|
35
37
|
return (
|
|
36
38
|
<>
|
|
39
|
+
{showTopError && (
|
|
40
|
+
<div className={styles["test-result-errors"]}>
|
|
41
|
+
<TrError {...error} status={status} />
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
37
44
|
{Boolean(pwTraces?.length) && <TrPwTraces pwTraces={pwTraces} />}
|
|
38
45
|
{Boolean(parameters?.length) && <TrParameters id={testResultId} parameters={parameters} />}
|
|
39
46
|
{Boolean(groupedLabels && Object.keys(groupedLabels || {})?.length) && (
|
|
@@ -4,6 +4,7 @@ import type { FunctionalComponent } from "preact";
|
|
|
4
4
|
import { useState } from "preact/hooks";
|
|
5
5
|
import type { AwesomeTestResult } from "types";
|
|
6
6
|
|
|
7
|
+
import { hasErrorDiff } from "@/components/TestResult/bodyItems";
|
|
7
8
|
import { TrError } from "@/components/TestResult/TrError";
|
|
8
9
|
import { useI18n } from "@/stores/locale";
|
|
9
10
|
import { navigateToTestResult } from "@/stores/router";
|
|
@@ -22,13 +23,15 @@ export const TrRetriesItem: FunctionalComponent<TrRetriesItemProps> = ({ testRes
|
|
|
22
23
|
const [isOpened, setIsOpen] = useState(false);
|
|
23
24
|
|
|
24
25
|
const { t } = useI18n("ui");
|
|
26
|
+
const { t: controls } = useI18n("controls");
|
|
25
27
|
|
|
26
28
|
const retryTitlePrefix = t("attempt", { attempt, total: totalAttempts });
|
|
27
29
|
const convertedStop = stop ? timestampToDate(stop) : undefined;
|
|
28
30
|
const retryTitle = convertedStop ? `${retryTitlePrefix} – ${convertedStop}` : retryTitlePrefix;
|
|
29
31
|
|
|
30
32
|
const formattedDuration = typeof duration === "number" ? formatDuration(duration) : undefined;
|
|
31
|
-
const
|
|
33
|
+
const errorPreview = getErrorPreview(error, controls("comparison"));
|
|
34
|
+
const hasErrorDetails = Boolean(errorPreview);
|
|
32
35
|
|
|
33
36
|
return (
|
|
34
37
|
<div data-testid="test-result-retries-item">
|
|
@@ -45,6 +48,16 @@ export const TrRetriesItem: FunctionalComponent<TrRetriesItemProps> = ({ testRes
|
|
|
45
48
|
<Text data-testid="test-result-retries-item-text" className={styles["test-result-retries-item-text"]}>
|
|
46
49
|
{retryTitle}
|
|
47
50
|
</Text>
|
|
51
|
+
{errorPreview && (
|
|
52
|
+
<Text
|
|
53
|
+
data-testid="test-result-retries-item-error-preview"
|
|
54
|
+
type="ui"
|
|
55
|
+
size="s"
|
|
56
|
+
className={styles["test-result-retries-item-error-preview"]}
|
|
57
|
+
>
|
|
58
|
+
{errorPreview}
|
|
59
|
+
</Text>
|
|
60
|
+
)}
|
|
48
61
|
<div className={styles["test-result-retries-item-info"]}>
|
|
49
62
|
{Boolean(formattedDuration) && (
|
|
50
63
|
<Text type="ui" size={"s"} className={styles["item-time"]}>
|
|
@@ -70,3 +83,16 @@ export const TrRetriesItem: FunctionalComponent<TrRetriesItemProps> = ({ testRes
|
|
|
70
83
|
</div>
|
|
71
84
|
);
|
|
72
85
|
};
|
|
86
|
+
|
|
87
|
+
const getErrorPreview = (error: AwesomeTestResult["error"], diffPreview: string) => {
|
|
88
|
+
const message = error?.message?.trim();
|
|
89
|
+
if (message) return message;
|
|
90
|
+
|
|
91
|
+
const tracePreview = error?.trace
|
|
92
|
+
?.split(/\r?\n/)
|
|
93
|
+
.map((line) => line.trim())
|
|
94
|
+
.find(Boolean);
|
|
95
|
+
if (tracePreview) return tracePreview;
|
|
96
|
+
|
|
97
|
+
if (hasErrorDiff(error)) return diffPreview;
|
|
98
|
+
};
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
|
|
21
21
|
.test-result-retries-item-wrap {
|
|
22
22
|
transition: background-color 300ms;
|
|
23
|
-
display:
|
|
23
|
+
display: grid;
|
|
24
|
+
grid-template-columns: auto auto minmax(0, 1fr) max-content;
|
|
24
25
|
gap: 4px;
|
|
25
|
-
justify-content: space-between;
|
|
26
26
|
border-radius: 6px;
|
|
27
27
|
padding: 4px;
|
|
28
28
|
width: 100%;
|
|
29
|
-
align-items:
|
|
29
|
+
align-items: center;
|
|
30
30
|
|
|
31
31
|
&:hover {
|
|
32
32
|
background: var(--color-row-bg-hover);
|
|
@@ -34,20 +34,30 @@
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
.test-result-retries-item-text {
|
|
37
|
-
|
|
37
|
+
flex: 0 0 auto;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.test-result-retries-item-error-preview {
|
|
41
|
+
flex: 1 1 auto;
|
|
42
|
+
color: var(--on-text-secondary);
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
text-overflow: ellipsis;
|
|
45
|
+
white-space: nowrap;
|
|
46
|
+
min-width: 0;
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
.test-result-retries-item-info {
|
|
41
50
|
display: flex;
|
|
42
51
|
gap: 4px;
|
|
43
52
|
align-items: center;
|
|
44
|
-
|
|
53
|
+
justify-content: flex-end;
|
|
54
|
+
margin-left: 8px;
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
.item-time {
|
|
48
|
-
margin-left: auto;
|
|
49
|
-
line-height: 20px;
|
|
50
58
|
color: var(--color-text-secondary);
|
|
59
|
+
line-height: 16px;
|
|
60
|
+
white-space: nowrap;
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
.test-result-retries-item-content {
|
|
@@ -46,7 +46,7 @@ export const TrSetup: FunctionalComponent<TrSetupProps> = ({ setup, id }) => {
|
|
|
46
46
|
<div className={styles["test-result-steps-root"]}>
|
|
47
47
|
{setup?.map((fixture, key) => (
|
|
48
48
|
<div className={styles["test-result-step-root"]} key={fixture.id}>
|
|
49
|
-
<TrStep item={fixtureResultToTrStepItem(fixture)} stepIndex={key + 1} />
|
|
49
|
+
<TrStep item={fixtureResultToTrStepItem(fixture)} stepIndex={key + 1} isTopLevel={true} />
|
|
50
50
|
</div>
|
|
51
51
|
))}
|
|
52
52
|
</div>
|
|
@@ -104,7 +104,8 @@ export const TrAttachment: FunctionComponent<{
|
|
|
104
104
|
event.stopPropagation();
|
|
105
105
|
openModal({
|
|
106
106
|
data: item,
|
|
107
|
-
|
|
107
|
+
preview: isPreviewable,
|
|
108
|
+
component: <Attachment item={item} previewable={isPreviewable} />,
|
|
108
109
|
});
|
|
109
110
|
};
|
|
110
111
|
|
|
@@ -47,10 +47,11 @@ export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({
|
|
|
47
47
|
event.stopPropagation();
|
|
48
48
|
openModal({
|
|
49
49
|
data: item,
|
|
50
|
+
preview: isPreviewable,
|
|
50
51
|
component: (
|
|
51
52
|
<Attachment
|
|
52
53
|
item={item}
|
|
53
|
-
previewable={
|
|
54
|
+
previewable={isPreviewable}
|
|
54
55
|
i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }}
|
|
55
56
|
/>
|
|
56
57
|
),
|
|
@@ -62,10 +63,17 @@ export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({
|
|
|
62
63
|
openModal({
|
|
63
64
|
isModalOpen: true,
|
|
64
65
|
data: item,
|
|
65
|
-
|
|
66
|
+
preview: isPreviewable,
|
|
67
|
+
component: (
|
|
68
|
+
<Attachment
|
|
69
|
+
item={item}
|
|
70
|
+
previewable={isPreviewable}
|
|
71
|
+
i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }}
|
|
72
|
+
/>
|
|
73
|
+
),
|
|
66
74
|
});
|
|
67
75
|
}
|
|
68
|
-
}, [item, tAttachments]);
|
|
76
|
+
}, [item, isPreviewable, tAttachments]);
|
|
69
77
|
|
|
70
78
|
const downloadData = async (e: MouseEvent) => {
|
|
71
79
|
e.stopPropagation();
|
|
@@ -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
|
|
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":
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
collectExpandableStepNodes,
|
|
17
17
|
hasStepContent,
|
|
18
18
|
getStepTreeExpansionPolicy,
|
|
19
|
+
isOpenByDefaultForPolicy,
|
|
19
20
|
isStepOpenedByDefault,
|
|
20
21
|
type SubtreeNode,
|
|
21
22
|
} from "@/components/TestResult/TrSteps/stepTreeExpansion";
|
|
@@ -70,7 +71,8 @@ export const TrStepsContent = (props: { item: TrStepItem }) => {
|
|
|
70
71
|
export const TrStep: FunctionComponent<{
|
|
71
72
|
item: TrStepItem;
|
|
72
73
|
stepIndex?: number;
|
|
73
|
-
|
|
74
|
+
isTopLevel?: boolean;
|
|
75
|
+
}> = ({ item, stepIndex, isTopLevel }) => {
|
|
74
76
|
const { item: stepData, bodyItems, suppressInlineError } = item;
|
|
75
77
|
const inlineError = {
|
|
76
78
|
message: stepData.message ?? stepData.error?.message,
|
|
@@ -85,7 +87,9 @@ export const TrStep: FunctionComponent<{
|
|
|
85
87
|
);
|
|
86
88
|
const policy = getStepTreeExpansionPolicy();
|
|
87
89
|
const hasContent = hasStepContent(item);
|
|
88
|
-
const openedByDefault =
|
|
90
|
+
const openedByDefault = isTopLevel
|
|
91
|
+
? isOpenByDefaultForPolicy(policy, true)
|
|
92
|
+
: isStepOpenedByDefault(policy, stepData.status, bodyItems);
|
|
89
93
|
const isOpened = isTreeOpened(stepData.stepId, openedByDefault);
|
|
90
94
|
const expandableDescendantNodes = collectExpandableStepNodes(bodyItems, policy);
|
|
91
95
|
const hasExpandableDescendants = expandableDescendantNodes.length > 0;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getNextSubtreeToggleState,
|
|
3
|
+
getSubtreeToggleIcon,
|
|
4
|
+
isSubtreeFirstLevelOnlyOpened,
|
|
5
|
+
type SubtreeToggleState,
|
|
6
|
+
} from "@allurereport/web-commons";
|
|
2
7
|
import { IconButton, allureIcons } from "@allurereport/web-components";
|
|
3
8
|
import type { FunctionalComponent } from "preact";
|
|
4
9
|
import { useState } from "preact/hooks";
|
|
@@ -8,9 +13,7 @@ import { TrDropdown } from "@/components/TestResult/TrDropdown";
|
|
|
8
13
|
import {
|
|
9
14
|
collectExpandableStepNodes,
|
|
10
15
|
getStepTreeExpansionPolicy,
|
|
11
|
-
hasFailedStepContext,
|
|
12
16
|
isOpenByDefaultForPolicy,
|
|
13
|
-
isSubtreeFirstLevelOnlyOpened,
|
|
14
17
|
type SubtreeNode,
|
|
15
18
|
} from "@/components/TestResult/TrSteps/stepTreeExpansion";
|
|
16
19
|
import { TrBodyItems } from "@/components/TestResult/TrSteps/TrBodyItems";
|
|
@@ -35,7 +38,7 @@ export type TrStepsProps = {
|
|
|
35
38
|
export const TrSteps: FunctionalComponent<TrStepsProps> = ({ bodyItems, id }) => {
|
|
36
39
|
const stepsId = typeof id === "string" ? `${id}-steps` : null;
|
|
37
40
|
const policy = getStepTreeExpansionPolicy();
|
|
38
|
-
const isRootOpenedByDefault = isOpenByDefaultForPolicy(policy,
|
|
41
|
+
const isRootOpenedByDefault = isOpenByDefaultForPolicy(policy, true);
|
|
39
42
|
const isOpened = stepsId !== null ? isTreeOpened(stepsId, isRootOpenedByDefault) : isRootOpenedByDefault;
|
|
40
43
|
const expandableTreeNodes = collectExpandableStepNodes(bodyItems, policy);
|
|
41
44
|
const hasChildren = stepsId !== null && bodyItems.length > 0;
|
|
@@ -118,7 +121,7 @@ export const TrSteps: FunctionalComponent<TrStepsProps> = ({ bodyItems, id }) =>
|
|
|
118
121
|
/>
|
|
119
122
|
{isOpened && (
|
|
120
123
|
<div data-testid="test-result-steps-root" className={styles["test-result-steps-root"]}>
|
|
121
|
-
<TrBodyItems bodyItems={bodyItems} />
|
|
124
|
+
<TrBodyItems bodyItems={bodyItems} isTopLevel={true} />
|
|
122
125
|
</div>
|
|
123
126
|
)}
|
|
124
127
|
</div>
|
|
@@ -47,7 +47,7 @@ export const TrTeardown: FunctionalComponent<TrTeardownProps> = ({ teardown, id
|
|
|
47
47
|
<div className={styles["test-result-steps-root"]}>
|
|
48
48
|
{teardown?.map((fixture, key) => (
|
|
49
49
|
<div className={styles["test-result-step-root"]} key={fixture.id}>
|
|
50
|
-
<TrStep item={fixtureResultToTrStepItem(fixture)} stepIndex={key + 1} />
|
|
50
|
+
<TrStep item={fixtureResultToTrStepItem(fixture)} stepIndex={key + 1} isTopLevel={true} />
|
|
51
51
|
</div>
|
|
52
52
|
))}
|
|
53
53
|
</div>
|
|
@@ -13,7 +13,7 @@ import { TrOverview } from "@/components/TestResult/TrOverview";
|
|
|
13
13
|
import { TrRetriesView } from "@/components/TestResult/TrRetriesView";
|
|
14
14
|
import { TrTabs } from "@/components/TestResult/TrTabs";
|
|
15
15
|
import { fetchTestEnvGroup } from "@/stores/env";
|
|
16
|
-
import {
|
|
16
|
+
import { focusTestResultPane } from "@/stores/keyboard";
|
|
17
17
|
import { isSplitMode } from "@/stores/layout";
|
|
18
18
|
import { trCurrentTab } from "@/stores/testResult";
|
|
19
19
|
|
|
@@ -59,7 +59,6 @@ const TrContent: FunctionalComponent<TrContentProps> = ({ testResult }) => {
|
|
|
59
59
|
|
|
60
60
|
const TestResult: FunctionComponent<TrProps> = ({ testResult }) => {
|
|
61
61
|
const split = isSplitMode.value;
|
|
62
|
-
const trPaneActive = split && activePane.value === "testResult";
|
|
63
62
|
|
|
64
63
|
useEffect(() => {
|
|
65
64
|
const testCaseId = testResult?.testCase?.id;
|
|
@@ -72,7 +71,7 @@ const TestResult: FunctionComponent<TrProps> = ({ testResult }) => {
|
|
|
72
71
|
return (
|
|
73
72
|
<>
|
|
74
73
|
<div
|
|
75
|
-
className={clsx(styles.content, split && styles["scroll-inside"]
|
|
74
|
+
className={clsx(styles.content, split && styles["scroll-inside"])}
|
|
76
75
|
data-tr-scroll-container
|
|
77
76
|
onMouseDown={() => focusTestResultPane()}
|
|
78
77
|
>
|
|
@@ -58,9 +58,29 @@ export const TreeList = () => {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const flatNode = getFlatTreeNode(focusedId);
|
|
61
|
-
|
|
61
|
+
const kind = flatNode?.kind;
|
|
62
|
+
|
|
63
|
+
scrollFocusIntoView(node, { kind });
|
|
62
64
|
}, [focusedId]);
|
|
63
65
|
|
|
66
|
+
useLayoutEffect(() => {
|
|
67
|
+
if (!trId || focusedId) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Use flatTree to find the scoped node id — avoids duplicate id issues in multi-env trees
|
|
72
|
+
const flatNode = flatTree.value.find((n) => n.testResultId === trId || n.id === trId);
|
|
73
|
+
const node = flatNode
|
|
74
|
+
? (document.querySelector(`[data-tree-node-id="${flatNode.id}"]`) as HTMLElement | null)
|
|
75
|
+
: document.getElementById(trId);
|
|
76
|
+
|
|
77
|
+
if (!node) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
scrollFocusIntoView(node, { kind: "leaf" });
|
|
82
|
+
}, [trId]);
|
|
83
|
+
|
|
64
84
|
const localizers = useMemo(
|
|
65
85
|
() => ({
|
|
66
86
|
tooltip: (key: string, options: Record<string, string>) => tooltip(`description.${key}`, options),
|
package/src/locales/ar.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "نسخ البريد الإلكتروني",
|
|
152
152
|
"attempt": "المحاولة {{attempt}} من {{total}}",
|
|
153
153
|
"at": "في",
|
|
154
|
+
"generated": "تم الإنشاء",
|
|
154
155
|
"variables": "المتغيرات",
|
|
155
156
|
"openPwTrace": "فتح تتبع Playwright",
|
|
156
157
|
"finishedAtOriginal": "{{formattedCreatedAt}}، برمز خروج {{original}}",
|
package/src/locales/az.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "E-poçtu kopyala",
|
|
152
152
|
"attempt": "Cəhd {{attempt}} / {{total}}",
|
|
153
153
|
"at": "tarixində",
|
|
154
|
+
"generated": "Yaradıldı",
|
|
154
155
|
"variables": "Dəyişənlər",
|
|
155
156
|
"openPwTrace": "Playwright Trace-i aç",
|
|
156
157
|
"pwTracePopupBlocked": "Brauzer Playwright Trace Viewer-i açmağı blokladı.",
|
package/src/locales/de.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "E-Mail kopieren",
|
|
152
152
|
"attempt": "Versuch {{attempt}} von {{total}}",
|
|
153
153
|
"at": "bei",
|
|
154
|
+
"generated": "Generiert",
|
|
154
155
|
"variables": "Variablen",
|
|
155
156
|
"openPwTrace": "Playwright Trace öffnen",
|
|
156
157
|
"pwTracePopupBlocked": "Der Browser hat das Öffnen des Playwright Trace Viewer blockiert.",
|
package/src/locales/en.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Copy email",
|
|
152
152
|
"attempt": "Attempt {{attempt}} of {{total}}",
|
|
153
153
|
"at": "at",
|
|
154
|
+
"generated": "Generated",
|
|
154
155
|
"variables": "Variables",
|
|
155
156
|
"openPwTrace": "Open Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "Browser blocked opening Playwright Trace Viewer.",
|
package/src/locales/es.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Copiar correo",
|
|
152
152
|
"attempt": "Intento {{attempt}} de {{total}}",
|
|
153
153
|
"at": "a las",
|
|
154
|
+
"generated": "Generado",
|
|
154
155
|
"variables": "Variables",
|
|
155
156
|
"openPwTrace": "Abrir Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "El navegador bloqueó la apertura de Playwright Trace Viewer.",
|
package/src/locales/fr.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Copier l'e-mail",
|
|
152
152
|
"attempt": "Tentative {{attempt}} sur {{total}}",
|
|
153
153
|
"at": "à",
|
|
154
|
+
"generated": "Généré",
|
|
154
155
|
"variables": "Variables",
|
|
155
156
|
"openPwTrace": "Ouvrir Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "Le navigateur a bloqué l’ouverture de Playwright Trace Viewer.",
|
package/src/locales/he.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "העתק אימייל",
|
|
152
152
|
"attempt": "ניסיון {{attempt}} מתוך {{total}}",
|
|
153
153
|
"at": "ב-",
|
|
154
|
+
"generated": "נוצר",
|
|
154
155
|
"variables": "משתנים",
|
|
155
156
|
"openPwTrace": "פתח Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "הדפדפן חסם את פתיחת Playwright Trace Viewer.",
|
package/src/locales/hy.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Պատճենել էլ. փոստը",
|
|
152
152
|
"attempt": "Փորձ {{attempt}}-ից {{total}}-ը",
|
|
153
153
|
"at": "է",
|
|
154
|
+
"generated": "Ստեղծվել է",
|
|
154
155
|
"variables": "Փոփոխականներ",
|
|
155
156
|
"openPwTrace": "Բացել Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "Բրաուզերը արգելափակեց Playwright Trace Viewer-ի բացումը։",
|
package/src/locales/it.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Copia email",
|
|
152
152
|
"attempt": "Tentativo {{attempt}} di {{total}}",
|
|
153
153
|
"at": "a",
|
|
154
|
+
"generated": "Generato",
|
|
154
155
|
"variables": "Variabili",
|
|
155
156
|
"openPwTrace": "Apri Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "Il browser ha bloccato l'apertura di Playwright Trace Viewer.",
|
package/src/locales/ja.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "メールをコピー",
|
|
152
152
|
"attempt": "試行 {{attempt}} 回目(全 {{total}} 回)",
|
|
153
153
|
"at": "時",
|
|
154
|
+
"generated": "生成日時",
|
|
154
155
|
"variables": "変数",
|
|
155
156
|
"openPwTrace": "Playwright Traceを開く",
|
|
156
157
|
"pwTracePopupBlocked": "ブラウザーが Playwright Trace Viewer の表示をブロックしました。",
|
package/src/locales/ka.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "ელფოსტის კოპირება",
|
|
152
152
|
"attempt": "მცდელობა {{attempt}} {{total}}-დან",
|
|
153
153
|
"at": "ზე",
|
|
154
|
+
"generated": "გენერირებულია",
|
|
154
155
|
"variables": "ცვლადები",
|
|
155
156
|
"openPwTrace": "გახსენი Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "ბრაუზერმა დაბლოკა Playwright Trace Viewer-ის გახსნა.",
|
package/src/locales/kr.json
CHANGED
package/src/locales/nl.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "E-mail kopiëren",
|
|
152
152
|
"attempt": "Poging {{attempt}} van {{total}}",
|
|
153
153
|
"at": "om",
|
|
154
|
+
"generated": "Gegenereerd",
|
|
154
155
|
"variables": "Variabelen",
|
|
155
156
|
"openPwTrace": "Open Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "De browser heeft het openen van Playwright Trace Viewer geblokkeerd.",
|