@allurereport/web-awesome 3.6.0 → 3.6.2
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/app-1c928f385beb78e2c2e8.js +2 -0
- package/dist/multi/{app-15cc636581486c011867.js.LICENSE.txt → app-1c928f385beb78e2c2e8.js.LICENSE.txt} +1 -1
- package/dist/multi/manifest.json +23 -23
- package/dist/multi/{styles-fd12e72f7e024e668bb4.css → styles-3515d3bdd45651cd4e66.css} +8 -8
- package/dist/single/app-16786ab64ac3e094685f.js +2 -0
- package/dist/single/{app-bbd6e33664f6d94cfaac.js.LICENSE.txt → app-16786ab64ac3e094685f.js.LICENSE.txt} +1 -1
- package/dist/single/manifest.json +1 -1
- package/package.json +6 -6
- package/src/components/Header/styles.scss +2 -1
- package/src/components/SectionSwitcher/styles.scss +1 -1
- package/src/components/SideBySide/index.tsx +1 -1
- package/src/components/SideBySide/styles.scss +6 -5
- package/src/components/TestResult/TrDropdown/index.tsx +7 -1
- package/src/components/TestResult/TrDropdown/styles.scss +7 -0
- package/src/components/TestResult/TrHeader/styles.scss +3 -0
- package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +4 -3
- package/src/components/TestResult/TrRetriesView/index.tsx +2 -2
- package/src/components/TestResult/TrSetup/index.tsx +6 -16
- package/src/components/TestResult/TrSteps/TrAttachment.tsx +3 -3
- package/src/components/TestResult/TrSteps/TrErrorStep.tsx +9 -3
- package/src/components/TestResult/TrSteps/TrStep.tsx +113 -8
- package/src/components/TestResult/TrSteps/TrStepHeader.tsx +3 -0
- package/src/components/TestResult/TrSteps/index.tsx +90 -5
- package/src/components/TestResult/TrSteps/stepTreeExpansion.ts +101 -0
- package/src/components/TestResult/TrSteps/styles.scss +12 -0
- package/src/components/TestResult/TrTeardown/index.tsx +6 -16
- package/src/components/TestResult/bodyItems.ts +26 -1
- package/src/components/Tree/index.tsx +7 -2
- package/src/components/Tree/styles.scss +1 -1
- package/src/index.tsx +13 -2
- package/src/stores/env.ts +6 -3
- package/src/stores/envInfo.ts +2 -2
- package/src/stores/sections.ts +3 -1
- package/src/stores/stats.ts +3 -3
- package/src/stores/tree.ts +40 -8
- package/test/components/TestResult/bodyItems.test.ts +25 -2
- package/test/components/TestResult/stepTreeExpansion.test.ts +179 -0
- package/types.d.ts +2 -0
- package/webpack.config.js +15 -3
- package/dist/multi/app-15cc636581486c011867.js +0 -2
- package/dist/single/app-bbd6e33664f6d94cfaac.js +0 -2
- /package/dist/multi/{173.app-15cc636581486c011867.js → 173.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{174.app-15cc636581486c011867.js → 174.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{252.app-15cc636581486c011867.js → 252.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{282.app-15cc636581486c011867.js → 282.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{29.app-15cc636581486c011867.js → 29.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{310.app-15cc636581486c011867.js → 310.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{416.app-15cc636581486c011867.js → 416.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{507.app-15cc636581486c011867.js → 507.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{527.app-15cc636581486c011867.js → 527.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{600.app-15cc636581486c011867.js → 600.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{605.app-15cc636581486c011867.js → 605.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{638.app-15cc636581486c011867.js → 638.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{672.app-15cc636581486c011867.js → 672.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{686.app-15cc636581486c011867.js → 686.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{725.app-15cc636581486c011867.js → 725.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{741.app-15cc636581486c011867.js → 741.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{749.app-15cc636581486c011867.js → 749.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{755.app-15cc636581486c011867.js → 755.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{894.app-15cc636581486c011867.js → 894.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{943.app-15cc636581486c011867.js → 943.app-1c928f385beb78e2c2e8.js} +0 -0
- /package/dist/multi/{980.app-15cc636581486c011867.js → 980.app-1c928f385beb78e2c2e8.js} +0 -0
|
@@ -0,0 +1,101 @@
|
|
|
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";
|
|
10
|
+
|
|
11
|
+
import { hasTestLevelErrorContent, type TrBodyItem, type TrStepItem } from "@/components/TestResult/bodyItems";
|
|
12
|
+
|
|
13
|
+
import type { AwesomeReportOptions, StepTreeExpansion } from "../../../../types";
|
|
14
|
+
|
|
15
|
+
const DEFAULT_STEP_TREE_EXPANSION_POLICY: StepTreeExpansion = "expand_failed_only";
|
|
16
|
+
|
|
17
|
+
const isFailedStatus = (status: TestStatus) => status === "failed" || status === "broken";
|
|
18
|
+
|
|
19
|
+
export const hasFailedStepContext = (bodyItems: TrBodyItem[]): boolean =>
|
|
20
|
+
bodyItems.some((bodyItem) => {
|
|
21
|
+
if (bodyItem.type === "step") {
|
|
22
|
+
return isFailedStatus(bodyItem.item.status) || hasFailedStepContext(bodyItem.bodyItems);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (bodyItem.type === "error") {
|
|
26
|
+
return isFailedStatus(bodyItem.status);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return false;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const hasInlineStepError = (stepItem: TrStepItem) => {
|
|
33
|
+
const { item: stepData, suppressInlineError } = stepItem;
|
|
34
|
+
return Boolean((stepData.message || stepData.trace) && !stepData.hasSimilarErrorInSubSteps && !suppressInlineError);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const hasStepContent = (stepItem: TrStepItem): boolean => {
|
|
38
|
+
return Boolean(stepItem.bodyItems.length || stepItem.item.parameters?.length || hasInlineStepError(stepItem));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const isStepOpenedByDefault = (
|
|
42
|
+
policy: StepTreeExpansion,
|
|
43
|
+
status: TestStatus,
|
|
44
|
+
bodyItems: TrBodyItem[],
|
|
45
|
+
): boolean => {
|
|
46
|
+
const hasFailedContext = status === "failed" || status === "broken" || hasFailedStepContext(bodyItems);
|
|
47
|
+
return isOpenByDefaultForPolicy(policy, hasFailedContext);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type ExpandableStepNode = {
|
|
51
|
+
id: string;
|
|
52
|
+
openedByDefault: boolean;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type SubtreeNode = SubtreeNodeState;
|
|
56
|
+
|
|
57
|
+
export const collectExpandableStepNodes = (
|
|
58
|
+
bodyItems: TrBodyItem[],
|
|
59
|
+
policy: StepTreeExpansion,
|
|
60
|
+
): ExpandableStepNode[] => {
|
|
61
|
+
const nodes: ExpandableStepNode[] = [];
|
|
62
|
+
|
|
63
|
+
bodyItems.forEach((bodyItem) => {
|
|
64
|
+
if (bodyItem.type === "step") {
|
|
65
|
+
if (hasStepContent(bodyItem)) {
|
|
66
|
+
nodes.push({
|
|
67
|
+
id: bodyItem.item.stepId,
|
|
68
|
+
openedByDefault: isStepOpenedByDefault(policy, bodyItem.item.status, bodyItem.bodyItems),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
nodes.push(...collectExpandableStepNodes(bodyItem.bodyItems, policy));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (bodyItem.type === "error" && hasTestLevelErrorContent(bodyItem.error)) {
|
|
76
|
+
nodes.push({
|
|
77
|
+
id: bodyItem.id,
|
|
78
|
+
openedByDefault: isOpenByDefaultForPolicy(policy, bodyItem.status === "failed" || bodyItem.status === "broken"),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return nodes;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export { getNextSubtreeToggleState, getSubtreeToggleIcon, isSubtreeFirstLevelOnlyOpened, type SubtreeToggleState };
|
|
87
|
+
|
|
88
|
+
export const getStepTreeExpansionPolicy = (): StepTreeExpansion =>
|
|
89
|
+
getReportOptions<AwesomeReportOptions>()?.stepTreeExpansion ?? DEFAULT_STEP_TREE_EXPANSION_POLICY;
|
|
90
|
+
|
|
91
|
+
export const isOpenByDefaultForPolicy = (policy: StepTreeExpansion, hasFailedContext: boolean): boolean => {
|
|
92
|
+
if (policy === "expanded") {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (policy === "collapsed") {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return hasFailedContext;
|
|
101
|
+
};
|
|
@@ -54,6 +54,18 @@
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
.test-result-step-subtree-toggle {
|
|
58
|
+
flex: 0 0 auto;
|
|
59
|
+
opacity: 0;
|
|
60
|
+
pointer-events: none;
|
|
61
|
+
transition: opacity 200ms;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.test-result-step-header:hover .test-result-step-subtree-toggle {
|
|
65
|
+
opacity: 1;
|
|
66
|
+
pointer-events: auto;
|
|
67
|
+
}
|
|
68
|
+
|
|
57
69
|
.test-result-header-text {
|
|
58
70
|
padding-left: 4px;
|
|
59
71
|
word-break: break-word;
|
|
@@ -3,21 +3,14 @@ import type { FunctionalComponent } from "preact";
|
|
|
3
3
|
import { useState } from "preact/hooks";
|
|
4
4
|
import type { AwesomeTestResult } from "types";
|
|
5
5
|
|
|
6
|
+
import { fixtureResultToTrStepItem } from "@/components/TestResult/bodyItems";
|
|
6
7
|
import { TrDropdown } from "@/components/TestResult/TrDropdown";
|
|
7
|
-
import { TrAttachment } from "@/components/TestResult/TrSteps/TrAttachment";
|
|
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
11
|
|
|
12
12
|
import * as styles from "@/components/TestResult/TrSteps/styles.scss";
|
|
13
13
|
|
|
14
|
-
const typeMap = {
|
|
15
|
-
before: TrStep,
|
|
16
|
-
after: TrStep,
|
|
17
|
-
step: TrStep,
|
|
18
|
-
attachment: TrAttachment,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
14
|
export type TrTeardownProps = {
|
|
22
15
|
teardown: AwesomeTestResult["teardown"];
|
|
23
16
|
id: string;
|
|
@@ -46,14 +39,11 @@ export const TrTeardown: FunctionalComponent<TrTeardownProps> = ({ teardown, id
|
|
|
46
39
|
/>
|
|
47
40
|
{isOpened && (
|
|
48
41
|
<div className={styles["test-result-steps-root"]}>
|
|
49
|
-
{teardown?.map((
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<StepComponent item={item} stepIndex={key + 1} key={key} className={styles["test-result-step-root"]} />
|
|
55
|
-
) : null;
|
|
56
|
-
})}
|
|
42
|
+
{teardown?.map((fixture, key) => (
|
|
43
|
+
<div className={styles["test-result-step-root"]} key={fixture.id}>
|
|
44
|
+
<TrStep item={fixtureResultToTrStepItem(fixture)} stepIndex={key + 1} />
|
|
45
|
+
</div>
|
|
46
|
+
))}
|
|
57
47
|
</div>
|
|
58
48
|
)}
|
|
59
49
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AttachmentTestStepResult, DefaultTestStepResult, TestError, TestStatus } from "@allurereport/core-api";
|
|
2
|
-
import type { AwesomeTestResult } from "types";
|
|
2
|
+
import type { AwesomeFixtureResult, AwesomeTestResult } from "types";
|
|
3
3
|
|
|
4
4
|
export type TestLevelErrorItem = {
|
|
5
5
|
type: "error";
|
|
@@ -128,6 +128,31 @@ const buildStepBodyItems = (
|
|
|
128
128
|
return { bodyItems, didPlaceSyntheticError };
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
+
export const getStepBodyItems = (steps: AwesomeTestResult["steps"]): TrBodyItem[] =>
|
|
132
|
+
buildStepBodyItems(steps, undefined).bodyItems;
|
|
133
|
+
|
|
134
|
+
export const fixtureResultToTrStepItem = (fixture: AwesomeFixtureResult): TrStepItem => {
|
|
135
|
+
const err = fixture.error;
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
type: "step",
|
|
139
|
+
item: {
|
|
140
|
+
type: "step",
|
|
141
|
+
name: fixture.name,
|
|
142
|
+
status: fixture.status,
|
|
143
|
+
parameters: [],
|
|
144
|
+
steps: fixture.steps,
|
|
145
|
+
stepId: fixture.id,
|
|
146
|
+
duration: fixture.duration,
|
|
147
|
+
message: err?.message,
|
|
148
|
+
trace: err?.trace,
|
|
149
|
+
error: err,
|
|
150
|
+
},
|
|
151
|
+
bodyItems: getStepBodyItems(fixture.steps),
|
|
152
|
+
suppressInlineError: false,
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
|
|
131
156
|
export const getBodyItems = (
|
|
132
157
|
testResult?: Pick<AwesomeTestResult, "id" | "status" | "steps" | "error">,
|
|
133
158
|
fallbackTitle = "Error",
|
|
@@ -72,15 +72,20 @@ export const TreeList = () => {
|
|
|
72
72
|
|
|
73
73
|
// render single tree for single environment
|
|
74
74
|
if (environmentsStore.value.data.length === 1) {
|
|
75
|
+
const soleId = environmentsStore.value.data[0]!.id;
|
|
76
|
+
const soleStatistic = currentEnvironment.value
|
|
77
|
+
? statsByEnvStore.value.data[currentEnvironment.value]
|
|
78
|
+
: statsByEnvStore.value.data[soleId];
|
|
79
|
+
|
|
75
80
|
return (
|
|
76
81
|
<div>
|
|
77
82
|
<Tree
|
|
78
83
|
reportStatistic={reportStatsStore.value.data}
|
|
79
|
-
statistic={
|
|
84
|
+
statistic={soleStatistic}
|
|
80
85
|
collapsedTrees={collapsedTrees.value}
|
|
81
86
|
toggleTree={toggleTree}
|
|
82
87
|
navigateTo={treeNavigateTo}
|
|
83
|
-
tree={treeLocalizer(filteredTree.value
|
|
88
|
+
tree={treeLocalizer(filteredTree.value[soleId])}
|
|
84
89
|
statusFilter={currentTreeStatus}
|
|
85
90
|
routeId={trId}
|
|
86
91
|
root
|
package/src/index.tsx
CHANGED
|
@@ -68,7 +68,7 @@ const App = () => {
|
|
|
68
68
|
await waitForI18next;
|
|
69
69
|
await Promise.all(fns.map((fn) => fn(currentEnvironment.value)));
|
|
70
70
|
|
|
71
|
-
const environmentIds = environmentsStore.value.data.map(({ id }) => id);
|
|
71
|
+
const environmentIds = environmentsStore.value.data.map(({ id }) => id).filter((id): id is string => Boolean(id));
|
|
72
72
|
|
|
73
73
|
if (currentEnvironment.value) {
|
|
74
74
|
await fetchEnvTreesData([currentEnvironment.value]);
|
|
@@ -83,7 +83,18 @@ const App = () => {
|
|
|
83
83
|
|
|
84
84
|
useEffect(() => {
|
|
85
85
|
prefetchData();
|
|
86
|
-
}, [
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
useSignalEffect(() => {
|
|
89
|
+
const envId = currentEnvironment.value;
|
|
90
|
+
|
|
91
|
+
if (!prefetched || !envId) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fetchEnvTreesData([envId]);
|
|
96
|
+
fetchEnvStats([envId]);
|
|
97
|
+
});
|
|
87
98
|
|
|
88
99
|
useSignalEffect(() => {
|
|
89
100
|
const testResultId = currentTrId.value;
|
package/src/stores/env.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type EnvironmentIdentity, type TestEnvGroup } from "@allurereport/core-api";
|
|
2
2
|
import {
|
|
3
3
|
environmentNameById as resolveEnvironmentNameById,
|
|
4
|
+
errorMessageFromUnknown,
|
|
4
5
|
fetchReportJsonData,
|
|
5
6
|
migrateStoredEnvironmentSelection,
|
|
7
|
+
normalizeEnvironmentsWidget,
|
|
6
8
|
} from "@allurereport/web-commons";
|
|
7
9
|
import { effect, signal } from "@preact/signals";
|
|
8
10
|
|
|
@@ -40,7 +42,8 @@ export const fetchEnvironments = async () => {
|
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
try {
|
|
43
|
-
const
|
|
45
|
+
const raw = await fetchReportJsonData<unknown>("widgets/environments.json", { bustCache: true });
|
|
46
|
+
const res = normalizeEnvironmentsWidget(raw);
|
|
44
47
|
|
|
45
48
|
environmentsStore.value = {
|
|
46
49
|
data: res,
|
|
@@ -52,7 +55,7 @@ export const fetchEnvironments = async () => {
|
|
|
52
55
|
} catch (e) {
|
|
53
56
|
environmentsStore.value = {
|
|
54
57
|
...environmentsStore.peek(),
|
|
55
|
-
error: e
|
|
58
|
+
error: errorMessageFromUnknown(e),
|
|
56
59
|
loading: false,
|
|
57
60
|
};
|
|
58
61
|
}
|
|
@@ -83,7 +86,7 @@ export const fetchTestEnvGroup = async (id: string) => {
|
|
|
83
86
|
} catch (e) {
|
|
84
87
|
testEnvGroupsStore.value = {
|
|
85
88
|
...testEnvGroupsStore.peek(),
|
|
86
|
-
error: e
|
|
89
|
+
error: errorMessageFromUnknown(e),
|
|
87
90
|
loading: false,
|
|
88
91
|
};
|
|
89
92
|
}
|
package/src/stores/envInfo.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EnvironmentItem } from "@allurereport/core-api";
|
|
2
|
-
import { fetchReportJsonData } from "@allurereport/web-commons";
|
|
2
|
+
import { errorMessageFromUnknown, fetchReportJsonData } from "@allurereport/web-commons";
|
|
3
3
|
import { signal } from "@preact/signals";
|
|
4
4
|
|
|
5
5
|
import type { StoreSignalState } from "@/stores/types";
|
|
@@ -28,7 +28,7 @@ export const fetchEnvInfo = async () => {
|
|
|
28
28
|
} catch (e) {
|
|
29
29
|
envInfoStore.value = {
|
|
30
30
|
...envInfoStore.peek(),
|
|
31
|
-
error: e
|
|
31
|
+
error: errorMessageFromUnknown(e),
|
|
32
32
|
loading: false,
|
|
33
33
|
};
|
|
34
34
|
}
|
package/src/stores/sections.ts
CHANGED
|
@@ -25,7 +25,9 @@ const onInit = () => {
|
|
|
25
25
|
|
|
26
26
|
onInit();
|
|
27
27
|
|
|
28
|
-
export const currentSection = computed(() =>
|
|
28
|
+
export const currentSection = computed(() =>
|
|
29
|
+
sectionRoute.value.matches ? (sectionRoute.value.params.section ?? "default") : "default",
|
|
30
|
+
);
|
|
29
31
|
|
|
30
32
|
effect(() => {
|
|
31
33
|
const section = currentSection.value;
|
package/src/stores/stats.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Statistic } from "@allurereport/core-api";
|
|
2
|
-
import { fetchReportJsonData } from "@allurereport/web-commons";
|
|
2
|
+
import { errorMessageFromUnknown, fetchReportJsonData } from "@allurereport/web-commons";
|
|
3
3
|
import { signal } from "@preact/signals";
|
|
4
4
|
|
|
5
5
|
import type { StoreSignalState } from "@/stores/types";
|
|
@@ -38,7 +38,7 @@ export const fetchReportStats = async () => {
|
|
|
38
38
|
} catch (err) {
|
|
39
39
|
reportStatsStore.value = {
|
|
40
40
|
data: { total: 0 },
|
|
41
|
-
error: err
|
|
41
|
+
error: errorMessageFromUnknown(err),
|
|
42
42
|
loading: false,
|
|
43
43
|
};
|
|
44
44
|
}
|
|
@@ -80,7 +80,7 @@ export const fetchEnvStats = async (envs: string[]) => {
|
|
|
80
80
|
} catch (err) {
|
|
81
81
|
statsByEnvStore.value = {
|
|
82
82
|
...statsByEnvStore.peek(),
|
|
83
|
-
error: err
|
|
83
|
+
error: errorMessageFromUnknown(err),
|
|
84
84
|
loading: false,
|
|
85
85
|
};
|
|
86
86
|
}
|
package/src/stores/tree.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildFilterPredicate, fetchReportJsonData } from "@allurereport/web-commons";
|
|
1
|
+
import { buildFilterPredicate, errorMessageFromUnknown, fetchReportJsonData } from "@allurereport/web-commons";
|
|
2
2
|
import type { RecursiveTree } from "@allurereport/web-components/global";
|
|
3
3
|
import { computed, effect, signal } from "@preact/signals";
|
|
4
4
|
import type { AwesomeTree, AwesomeTreeGroup } from "types";
|
|
@@ -23,19 +23,51 @@ export const noTests = computed(() => {
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export const collapsedTrees = signal(new Set(loadFromLocalStorage<string[]>("collapsedTrees", [])));
|
|
26
|
+
export const expandedTrees = signal(new Set(loadFromLocalStorage<string[]>("expandedTrees", [])));
|
|
26
27
|
|
|
27
28
|
effect(() => {
|
|
28
29
|
localStorage.setItem("collapsedTrees", JSON.stringify([...collapsedTrees.value]));
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
effect(() => {
|
|
33
|
+
localStorage.setItem("expandedTrees", JSON.stringify([...expandedTrees.value]));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const isTreeOpened = (id: string, openedByDefault = true): boolean => {
|
|
37
|
+
if (openedByDefault) {
|
|
38
|
+
return !collapsedTrees.value.has(id);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return expandedTrees.value.has(id);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const setTreeStoredState = (id: string, shouldBeOpened: boolean, openedByDefault: boolean) => {
|
|
45
|
+
if (openedByDefault) {
|
|
46
|
+
const nextCollapsedTrees = new Set(collapsedTrees.value);
|
|
47
|
+
if (shouldBeOpened) {
|
|
48
|
+
nextCollapsedTrees.delete(id);
|
|
49
|
+
} else {
|
|
50
|
+
nextCollapsedTrees.add(id);
|
|
51
|
+
}
|
|
52
|
+
collapsedTrees.value = nextCollapsedTrees;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const nextExpandedTrees = new Set(expandedTrees.value);
|
|
57
|
+
if (shouldBeOpened) {
|
|
58
|
+
nextExpandedTrees.add(id);
|
|
35
59
|
} else {
|
|
36
|
-
|
|
60
|
+
nextExpandedTrees.delete(id);
|
|
37
61
|
}
|
|
38
|
-
|
|
62
|
+
expandedTrees.value = nextExpandedTrees;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const toggleTree = (id: string, openedByDefault = true) => {
|
|
66
|
+
setTreeStoredState(id, !isTreeOpened(id, openedByDefault), openedByDefault);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const setTreeOpened = (id: string, shouldBeOpened: boolean, openedByDefault = true) => {
|
|
70
|
+
setTreeStoredState(id, shouldBeOpened, openedByDefault);
|
|
39
71
|
};
|
|
40
72
|
|
|
41
73
|
export const fetchEnvTreesData = async (envs: string[]) => {
|
|
@@ -74,7 +106,7 @@ export const fetchEnvTreesData = async (envs: string[]) => {
|
|
|
74
106
|
} catch (e) {
|
|
75
107
|
treeStore.value = {
|
|
76
108
|
...treeStore.peek(),
|
|
77
|
-
error: e
|
|
109
|
+
error: errorMessageFromUnknown(e),
|
|
78
110
|
loading: false,
|
|
79
111
|
};
|
|
80
112
|
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { AttachmentTestStepResult, DefaultTestStepResult } from "@allurereport/core-api";
|
|
2
|
-
import type { AwesomeTestResult } from "types";
|
|
2
|
+
import type { AwesomeFixtureResult, AwesomeTestResult } from "types";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
fixtureResultToTrStepItem,
|
|
7
|
+
getBodyItems,
|
|
8
|
+
getStepBodyItems,
|
|
9
|
+
getTestLevelErrorId,
|
|
10
|
+
} from "@/components/TestResult/bodyItems";
|
|
6
11
|
|
|
7
12
|
const sampleStep: DefaultTestStepResult = {
|
|
8
13
|
type: "step",
|
|
@@ -191,4 +196,22 @@ describe("components > TestResult > bodyItems", () => {
|
|
|
191
196
|
},
|
|
192
197
|
]);
|
|
193
198
|
});
|
|
199
|
+
|
|
200
|
+
it("fixtureResultToTrStepItem builds TrStepItem from setup or teardown fixture", () => {
|
|
201
|
+
const fixture: AwesomeFixtureResult = {
|
|
202
|
+
id: "fixture-before-1",
|
|
203
|
+
type: "before",
|
|
204
|
+
name: "before suite",
|
|
205
|
+
status: "passed",
|
|
206
|
+
steps: [sampleStep],
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const wrapped = fixtureResultToTrStepItem(fixture);
|
|
210
|
+
|
|
211
|
+
expect(wrapped.type).toBe("step");
|
|
212
|
+
expect(wrapped.item.name).toBe("before suite");
|
|
213
|
+
expect(wrapped.item.stepId).toBe("fixture-before-1");
|
|
214
|
+
expect(wrapped.item.type).toBe("step");
|
|
215
|
+
expect(wrapped.bodyItems).toEqual(getStepBodyItems([sampleStep]));
|
|
216
|
+
});
|
|
194
217
|
});
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import type { TrBodyItem } from "@/components/TestResult/bodyItems";
|
|
4
|
+
import {
|
|
5
|
+
collectExpandableStepNodes,
|
|
6
|
+
getNextSubtreeToggleState,
|
|
7
|
+
hasFailedStepContext,
|
|
8
|
+
isOpenByDefaultForPolicy,
|
|
9
|
+
isStepOpenedByDefault,
|
|
10
|
+
} from "@/components/TestResult/TrSteps/stepTreeExpansion";
|
|
11
|
+
|
|
12
|
+
describe("components > TestResult > stepTreeExpansion", () => {
|
|
13
|
+
it("should detect failed context in nested steps", () => {
|
|
14
|
+
const bodyItems = [
|
|
15
|
+
{
|
|
16
|
+
type: "step",
|
|
17
|
+
item: {
|
|
18
|
+
name: "top-level step",
|
|
19
|
+
status: "passed",
|
|
20
|
+
},
|
|
21
|
+
suppressInlineError: false,
|
|
22
|
+
bodyItems: [
|
|
23
|
+
{
|
|
24
|
+
type: "step",
|
|
25
|
+
item: {
|
|
26
|
+
name: "failed nested step",
|
|
27
|
+
status: "failed",
|
|
28
|
+
},
|
|
29
|
+
suppressInlineError: false,
|
|
30
|
+
bodyItems: [],
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
] as TrBodyItem[];
|
|
35
|
+
|
|
36
|
+
expect(hasFailedStepContext(bodyItems)).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should not detect failed context for only passed steps and attachments", () => {
|
|
40
|
+
const bodyItems = [
|
|
41
|
+
{
|
|
42
|
+
type: "step",
|
|
43
|
+
item: {
|
|
44
|
+
name: "top-level step",
|
|
45
|
+
status: "passed",
|
|
46
|
+
},
|
|
47
|
+
suppressInlineError: false,
|
|
48
|
+
bodyItems: [],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: "attachment",
|
|
52
|
+
link: {
|
|
53
|
+
id: "attachment-1",
|
|
54
|
+
source: "attachment-1.txt",
|
|
55
|
+
name: "attachment",
|
|
56
|
+
type: "text/plain",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
] as TrBodyItem[];
|
|
60
|
+
|
|
61
|
+
expect(hasFailedStepContext(bodyItems)).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should resolve default expansion state according to policy", () => {
|
|
65
|
+
expect(isOpenByDefaultForPolicy("expanded", false)).toBe(true);
|
|
66
|
+
expect(isOpenByDefaultForPolicy("collapsed", true)).toBe(false);
|
|
67
|
+
expect(isOpenByDefaultForPolicy("expand_failed_only", true)).toBe(true);
|
|
68
|
+
expect(isOpenByDefaultForPolicy("expand_failed_only", false)).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should resolve step default opening according to status and nested failures", () => {
|
|
72
|
+
const failedBodyItems = [
|
|
73
|
+
{
|
|
74
|
+
type: "step",
|
|
75
|
+
item: {
|
|
76
|
+
name: "nested failed step",
|
|
77
|
+
status: "failed",
|
|
78
|
+
},
|
|
79
|
+
suppressInlineError: false,
|
|
80
|
+
bodyItems: [],
|
|
81
|
+
},
|
|
82
|
+
] as TrBodyItem[];
|
|
83
|
+
|
|
84
|
+
expect(isStepOpenedByDefault("expand_failed_only", "passed", failedBodyItems)).toBe(true);
|
|
85
|
+
expect(isStepOpenedByDefault("expand_failed_only", "passed", [])).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("should collect expandable step and error nodes with correct defaults", () => {
|
|
89
|
+
const bodyItems = [
|
|
90
|
+
{
|
|
91
|
+
type: "step",
|
|
92
|
+
item: {
|
|
93
|
+
stepId: "parent-step",
|
|
94
|
+
name: "parent step",
|
|
95
|
+
status: "passed",
|
|
96
|
+
parameters: [],
|
|
97
|
+
message: "",
|
|
98
|
+
trace: "",
|
|
99
|
+
hasSimilarErrorInSubSteps: false,
|
|
100
|
+
},
|
|
101
|
+
suppressInlineError: false,
|
|
102
|
+
bodyItems: [
|
|
103
|
+
{
|
|
104
|
+
type: "step",
|
|
105
|
+
item: {
|
|
106
|
+
stepId: "failed-child-step",
|
|
107
|
+
name: "failed child step",
|
|
108
|
+
status: "failed",
|
|
109
|
+
parameters: [],
|
|
110
|
+
message: "child failed",
|
|
111
|
+
trace: "trace",
|
|
112
|
+
hasSimilarErrorInSubSteps: false,
|
|
113
|
+
},
|
|
114
|
+
suppressInlineError: false,
|
|
115
|
+
bodyItems: [],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
type: "error",
|
|
119
|
+
id: "test-error",
|
|
120
|
+
title: "Error",
|
|
121
|
+
status: "failed",
|
|
122
|
+
error: {
|
|
123
|
+
message: "failure",
|
|
124
|
+
trace: "trace",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
] as TrBodyItem[];
|
|
130
|
+
|
|
131
|
+
expect(collectExpandableStepNodes(bodyItems, "expand_failed_only")).toEqual([
|
|
132
|
+
{ id: "parent-step", openedByDefault: true },
|
|
133
|
+
{ id: "failed-child-step", openedByDefault: true },
|
|
134
|
+
{ id: "test-error", openedByDefault: true },
|
|
135
|
+
]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should calculate next subtree toggle state like categories", () => {
|
|
139
|
+
expect(
|
|
140
|
+
getNextSubtreeToggleState({
|
|
141
|
+
hasOnlyLeafResults: false,
|
|
142
|
+
isSubtreeCollapsedAll: true,
|
|
143
|
+
isSubtreeFirstLevelOnly: false,
|
|
144
|
+
isSubtreeExpandedAll: false,
|
|
145
|
+
lastSubtreeToggle: null,
|
|
146
|
+
}),
|
|
147
|
+
).toBe("first");
|
|
148
|
+
|
|
149
|
+
expect(
|
|
150
|
+
getNextSubtreeToggleState({
|
|
151
|
+
hasOnlyLeafResults: false,
|
|
152
|
+
isSubtreeCollapsedAll: false,
|
|
153
|
+
isSubtreeFirstLevelOnly: true,
|
|
154
|
+
isSubtreeExpandedAll: false,
|
|
155
|
+
lastSubtreeToggle: null,
|
|
156
|
+
}),
|
|
157
|
+
).toBe("all");
|
|
158
|
+
|
|
159
|
+
expect(
|
|
160
|
+
getNextSubtreeToggleState({
|
|
161
|
+
hasOnlyLeafResults: false,
|
|
162
|
+
isSubtreeCollapsedAll: false,
|
|
163
|
+
isSubtreeFirstLevelOnly: true,
|
|
164
|
+
isSubtreeExpandedAll: false,
|
|
165
|
+
lastSubtreeToggle: "all",
|
|
166
|
+
}),
|
|
167
|
+
).toBe("none");
|
|
168
|
+
|
|
169
|
+
expect(
|
|
170
|
+
getNextSubtreeToggleState({
|
|
171
|
+
hasOnlyLeafResults: true,
|
|
172
|
+
isSubtreeCollapsedAll: false,
|
|
173
|
+
isSubtreeFirstLevelOnly: false,
|
|
174
|
+
isSubtreeExpandedAll: true,
|
|
175
|
+
lastSubtreeToggle: "all",
|
|
176
|
+
}),
|
|
177
|
+
).toBe("none");
|
|
178
|
+
});
|
|
179
|
+
});
|
package/types.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
} from "@allurereport/core-api";
|
|
13
13
|
|
|
14
14
|
export type Layout = "base" | "split";
|
|
15
|
+
export type StepTreeExpansion = "collapsed" | "expand_failed_only" | "expanded";
|
|
15
16
|
|
|
16
17
|
export type AwesomeReportOptions = {
|
|
17
18
|
allureVersion: string;
|
|
@@ -27,6 +28,7 @@ export type AwesomeReportOptions = {
|
|
|
27
28
|
sections?: string[];
|
|
28
29
|
cacheKey: string;
|
|
29
30
|
ci?: CiDescriptor;
|
|
31
|
+
stepTreeExpansion?: StepTreeExpansion;
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
export type AwesomeFixtureResult = Omit<
|