@allurereport/web-awesome 3.0.0-beta.10

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 (196) hide show
  1. package/.babelrc.js +46 -0
  2. package/.eslintrc.cjs +18 -0
  3. package/CONTRIBUTING.md +34 -0
  4. package/README.md +27 -0
  5. package/dist/multi/141.app-d01d0c66.js +1 -0
  6. package/dist/multi/222.app-d01d0c66.js +1 -0
  7. package/dist/multi/335.app-d01d0c66.js +1 -0
  8. package/dist/multi/34.app-d01d0c66.js +1 -0
  9. package/dist/multi/349.app-d01d0c66.js +1 -0
  10. package/dist/multi/378.app-d01d0c66.js +1 -0
  11. package/dist/multi/406.app-d01d0c66.js +1 -0
  12. package/dist/multi/476.app-d01d0c66.js +1 -0
  13. package/dist/multi/53.app-d01d0c66.js +1 -0
  14. package/dist/multi/584.app-d01d0c66.js +1 -0
  15. package/dist/multi/690.app-d01d0c66.js +1 -0
  16. package/dist/multi/747.app-d01d0c66.js +1 -0
  17. package/dist/multi/767.app-d01d0c66.js +1 -0
  18. package/dist/multi/816.app-d01d0c66.js +1 -0
  19. package/dist/multi/83.app-d01d0c66.js +1 -0
  20. package/dist/multi/873.app-d01d0c66.js +1 -0
  21. package/dist/multi/920.app-d01d0c66.js +1 -0
  22. package/dist/multi/991.app-d01d0c66.js +1 -0
  23. package/dist/multi/JetBrainsMono_vf-9e9649b6..woff2 +0 -0
  24. package/dist/multi/JetBrainsMono_vf-b9a9c326..woff +0 -0
  25. package/dist/multi/app-d01d0c66.js +2 -0
  26. package/dist/multi/app-d01d0c66.js.LICENSE.txt +16 -0
  27. package/dist/multi/manifest.json +26 -0
  28. package/dist/multi/pt-root-ui_vf-22fe60ca..woff +0 -0
  29. package/dist/multi/pt-root-ui_vf-9d251e8b..woff2 +0 -0
  30. package/dist/multi/styles-d01d0c66.css +39 -0
  31. package/dist/single/app-6596cb08.js +2 -0
  32. package/dist/single/app-6596cb08.js.LICENSE.txt +16 -0
  33. package/dist/single/manifest.json +3 -0
  34. package/package.json +107 -0
  35. package/postcss.config.js +5 -0
  36. package/src/assets/scss/_common.scss +143 -0
  37. package/src/assets/scss/day.scss +51 -0
  38. package/src/assets/scss/fonts.scss +3 -0
  39. package/src/assets/scss/index.scss +7 -0
  40. package/src/assets/scss/night.scss +61 -0
  41. package/src/assets/scss/palette.scss +393 -0
  42. package/src/assets/scss/theme.scss +119 -0
  43. package/src/assets/scss/vars.scss +9 -0
  44. package/src/assets/svg/line-alerts-alert-circle.svg +12 -0
  45. package/src/assets/svg/line-general-eye.svg +7 -0
  46. package/src/assets/svg/line-icon-bomb-2.svg +12 -0
  47. package/src/components/ArrowButton/index.tsx +36 -0
  48. package/src/components/ArrowButton/styles.scss +35 -0
  49. package/src/components/BaseLayout/index.tsx +43 -0
  50. package/src/components/BaseLayout/styles.scss +60 -0
  51. package/src/components/Footer/FooterLogo.tsx +16 -0
  52. package/src/components/Footer/FooterVersion.tsx +37 -0
  53. package/src/components/Footer/index.tsx +13 -0
  54. package/src/components/Footer/styles.scss +14 -0
  55. package/src/components/Header/index.tsx +28 -0
  56. package/src/components/Header/styles.scss +33 -0
  57. package/src/components/LanguagePicker/index.tsx +40 -0
  58. package/src/components/MainReport/index.tsx +21 -0
  59. package/src/components/MainReport/styles.scss +11 -0
  60. package/src/components/Metadata/index.tsx +121 -0
  61. package/src/components/Metadata/styles.scss +146 -0
  62. package/src/components/MetadataButton/index.tsx +32 -0
  63. package/src/components/MetadataButton/styles.scss +53 -0
  64. package/src/components/Modal/index.tsx +22 -0
  65. package/src/components/ReportBody/Filters.tsx +90 -0
  66. package/src/components/ReportBody/HeaderActions.tsx +21 -0
  67. package/src/components/ReportBody/SortBy.tsx +132 -0
  68. package/src/components/ReportBody/context.tsx +106 -0
  69. package/src/components/ReportBody/index.tsx +72 -0
  70. package/src/components/ReportBody/styles.scss +69 -0
  71. package/src/components/ReportHeader/ReportHeaderLabelList.tsx +12 -0
  72. package/src/components/ReportHeader/ReportHeaderLogo.tsx +10 -0
  73. package/src/components/ReportHeader/ReportHeaderPie.tsx +14 -0
  74. package/src/components/ReportHeader/index.tsx +33 -0
  75. package/src/components/ReportHeader/styles.scss +51 -0
  76. package/src/components/ReportLogo/index.tsx +16 -0
  77. package/src/components/ReportLogo/styles.scss +20 -0
  78. package/src/components/ReportLogoFull/index.tsx +20 -0
  79. package/src/components/ReportLogoFull/styles.scss +7 -0
  80. package/src/components/ReportMetadata/MetadataItem.tsx +45 -0
  81. package/src/components/ReportMetadata/MetadataSummary.tsx +81 -0
  82. package/src/components/ReportMetadata/MetadataTestType.tsx +16 -0
  83. package/src/components/ReportMetadata/MetadataWithIcon.tsx +21 -0
  84. package/src/components/ReportMetadata/index.tsx +46 -0
  85. package/src/components/ReportMetadata/styles.scss +99 -0
  86. package/src/components/SideBySide/index.tsx +52 -0
  87. package/src/components/SideBySide/styles.scss +65 -0
  88. package/src/components/SplitLayout/index.tsx +77 -0
  89. package/src/components/SplitLayout/styles.scss +85 -0
  90. package/src/components/Tabs/index.tsx +62 -0
  91. package/src/components/Tabs/styles.scss +56 -0
  92. package/src/components/TestResult/TestResultAttachmentsView/index.tsx +27 -0
  93. package/src/components/TestResult/TestResultAttachmentsView/styles.scss +12 -0
  94. package/src/components/TestResult/TestResultDescription/index.tsx +27 -0
  95. package/src/components/TestResult/TestResultDescription/styles.scss +12 -0
  96. package/src/components/TestResult/TestResultDropdown/index.tsx +26 -0
  97. package/src/components/TestResult/TestResultDropdown/styles.scss +34 -0
  98. package/src/components/TestResult/TestResultEmpty/index.tsx +34 -0
  99. package/src/components/TestResult/TestResultEmpty/styles.scss +25 -0
  100. package/src/components/TestResult/TestResultHeader/TestResultBreadcrumbs.tsx +44 -0
  101. package/src/components/TestResult/TestResultHeader/index.tsx +21 -0
  102. package/src/components/TestResult/TestResultHeader/styles.scss +48 -0
  103. package/src/components/TestResult/TestResultHistory/TestResultHistoryItem.tsx +66 -0
  104. package/src/components/TestResult/TestResultHistory/index.tsx +26 -0
  105. package/src/components/TestResult/TestResultHistory/styles.scss +63 -0
  106. package/src/components/TestResult/TestResultInfo/TestResultInfoStatuses.tsx +30 -0
  107. package/src/components/TestResult/TestResultInfo/index.tsx +81 -0
  108. package/src/components/TestResult/TestResultInfo/styles.scss +68 -0
  109. package/src/components/TestResult/TestResultLinks/index.tsx +56 -0
  110. package/src/components/TestResult/TestResultLinks/styles.scss +30 -0
  111. package/src/components/TestResult/TestResultMetadata/index.tsx +27 -0
  112. package/src/components/TestResult/TestResultMetadata/styles.scss +8 -0
  113. package/src/components/TestResult/TestResultNavigation/index.tsx +80 -0
  114. package/src/components/TestResult/TestResultNavigation/styles.scss +48 -0
  115. package/src/components/TestResult/TestResultOverview.tsx +43 -0
  116. package/src/components/TestResult/TestResultParameters/index.tsx +30 -0
  117. package/src/components/TestResult/TestResultParameters/styles.scss +8 -0
  118. package/src/components/TestResult/TestResultPrevStatuses/index.tsx +49 -0
  119. package/src/components/TestResult/TestResultPrevStatuses/styles.scss +57 -0
  120. package/src/components/TestResult/TestResultRetriesView/TestResultRetriesItem.tsx +51 -0
  121. package/src/components/TestResult/TestResultRetriesView/index.tsx +24 -0
  122. package/src/components/TestResult/TestResultRetriesView/styles.scss +69 -0
  123. package/src/components/TestResult/TestResultSetup/index.tsx +58 -0
  124. package/src/components/TestResult/TestResultSeverity/index.tsx +27 -0
  125. package/src/components/TestResult/TestResultSeverity/styles.scss +29 -0
  126. package/src/components/TestResult/TestResultStatus/index.tsx +25 -0
  127. package/src/components/TestResult/TestResultStatus/styles.scss +36 -0
  128. package/src/components/TestResult/TestResultSteps/index.tsx +58 -0
  129. package/src/components/TestResult/TestResultSteps/styles.scss +225 -0
  130. package/src/components/TestResult/TestResultSteps/testResultAttachment.tsx +76 -0
  131. package/src/components/TestResult/TestResultSteps/testResultAttachmentInfo.tsx +83 -0
  132. package/src/components/TestResult/TestResultSteps/testResultStep.tsx +84 -0
  133. package/src/components/TestResult/TestResultSteps/testResultStepInfo.tsx +30 -0
  134. package/src/components/TestResult/TestResultSteps/wrongAttachment.tsx +8 -0
  135. package/src/components/TestResult/TestResultTabs/index.tsx +68 -0
  136. package/src/components/TestResult/TestResultTabs/styles.scss +76 -0
  137. package/src/components/TestResult/TestResultTeardown/index.tsx +59 -0
  138. package/src/components/TestResult/TestStepsEmpty/index.tsx +23 -0
  139. package/src/components/TestResult/TestStepsEmpty/styles.scss +25 -0
  140. package/src/components/TestResult/TrError/TrDiff.tsx +124 -0
  141. package/src/components/TestResult/TrError/index.tsx +78 -0
  142. package/src/components/TestResult/TrError/styles.scss +133 -0
  143. package/src/components/TestResult/index.tsx +62 -0
  144. package/src/components/TestResult/styles.scss +11 -0
  145. package/src/components/ThemeButton/ThemeButton.tsx +20 -0
  146. package/src/components/ToggleLayout/index.tsx +17 -0
  147. package/src/components/Tree/index.tsx +75 -0
  148. package/src/components/Tree/styles.scss +189 -0
  149. package/src/i18n/constants.ts +124 -0
  150. package/src/i18n/locales/am.json +133 -0
  151. package/src/i18n/locales/az.json +133 -0
  152. package/src/i18n/locales/de.json +133 -0
  153. package/src/i18n/locales/en.json +134 -0
  154. package/src/i18n/locales/es.json +133 -0
  155. package/src/i18n/locales/fr.json +133 -0
  156. package/src/i18n/locales/he.json +133 -0
  157. package/src/i18n/locales/it.json +133 -0
  158. package/src/i18n/locales/ja.json +133 -0
  159. package/src/i18n/locales/ka.json +133 -0
  160. package/src/i18n/locales/kr.json +133 -0
  161. package/src/i18n/locales/nl.json +133 -0
  162. package/src/i18n/locales/pl.json +131 -0
  163. package/src/i18n/locales/pt.json +133 -0
  164. package/src/i18n/locales/ru.json +131 -0
  165. package/src/i18n/locales/sv.json +133 -0
  166. package/src/i18n/locales/tr.json +133 -0
  167. package/src/i18n/locales/zh.json +133 -0
  168. package/src/index.html +40 -0
  169. package/src/index.tsx +96 -0
  170. package/src/stores/chart.ts +32 -0
  171. package/src/stores/envInfo.ts +34 -0
  172. package/src/stores/index.ts +4 -0
  173. package/src/stores/layout.ts +36 -0
  174. package/src/stores/locale.ts +75 -0
  175. package/src/stores/modal.ts +22 -0
  176. package/src/stores/router.ts +48 -0
  177. package/src/stores/stats.ts +36 -0
  178. package/src/stores/testResults.ts +66 -0
  179. package/src/stores/theme.ts +32 -0
  180. package/src/stores/tree.ts +157 -0
  181. package/src/stores/types.ts +5 -0
  182. package/src/styles.scss +45 -0
  183. package/src/types/globals.d.ts +13 -0
  184. package/src/types/window.d.ts +8 -0
  185. package/src/utils/capitalize.ts +6 -0
  186. package/src/utils/copyToClipboard.ts +16 -0
  187. package/src/utils/isMac.ts +8 -0
  188. package/src/utils/loadFromLocalStorage.ts +8 -0
  189. package/src/utils/statuses.ts +55 -0
  190. package/src/utils/time.ts +17 -0
  191. package/src/utils/treeFilters.ts +147 -0
  192. package/test/utils/treeFilters.test.ts +448 -0
  193. package/tsconfig.json +27 -0
  194. package/types.d.ts +99 -0
  195. package/vitest.config.ts +18 -0
  196. package/webpack.config.js +112 -0
@@ -0,0 +1,147 @@
1
+ import type { Comparator, DefaultTreeGroup, Statistic, TestStatus, TreeLeaf } from "@allurereport/core-api";
2
+ import {
3
+ alphabetically,
4
+ andThen,
5
+ byStatistic,
6
+ byStatus,
7
+ compareBy,
8
+ emptyStatistic,
9
+ incrementStatistic,
10
+ mergeStatistic,
11
+ ordinal,
12
+ reverse,
13
+ } from "@allurereport/core-api";
14
+ import type { TreeFiltersState, TreeSortBy } from "@/stores/tree";
15
+ import type { AwesomeRecursiveTree, AwesomeTree, AwesomeTreeGroup, AwesomeTreeLeaf } from "../../types";
16
+
17
+ export const isIncluded = (leaf: TreeLeaf<AwesomeTreeLeaf>, filterOptions: TreeFiltersState) => {
18
+ const queryMatched = !filterOptions?.query || leaf.name.toLowerCase().includes(filterOptions.query.toLowerCase());
19
+ const statusMatched =
20
+ !filterOptions?.status || filterOptions?.status === "total" || leaf.status === filterOptions.status;
21
+ const flakyMatched = !filterOptions?.filter?.flaky || leaf.flaky;
22
+ const retryMatched = !filterOptions?.filter?.retry || leaf.retry;
23
+ // TODO: at this moment we don't have a new field implementation even in the generator
24
+ // const newMatched = !filterOptions?.filter?.new || leaf.new;
25
+
26
+ return [queryMatched, statusMatched, flakyMatched, retryMatched].every(Boolean);
27
+ };
28
+
29
+ const leafComparatorByTreeSortBy = (sortBy: TreeSortBy = "status"): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
30
+ const typedCompareBy = compareBy<TreeLeaf<AwesomeTreeLeaf>>;
31
+ switch (sortBy) {
32
+ case "order":
33
+ return typedCompareBy("groupOrder", ordinal());
34
+ case "duration":
35
+ return typedCompareBy("duration", ordinal());
36
+ case "alphabet":
37
+ return typedCompareBy("name", alphabetically());
38
+ case "status":
39
+ return typedCompareBy("status", byStatus());
40
+ default:
41
+ // eslint-disable-next-line no-console
42
+ console.error(`unsupported comparator ${sortBy}`);
43
+ return () => 0;
44
+ }
45
+ };
46
+
47
+ const groupComparatorByTreeSortBy = (sortBy: TreeSortBy = "status"): Comparator<DefaultTreeGroup> => {
48
+ const typedCompareBy = compareBy<DefaultTreeGroup>;
49
+ switch (sortBy) {
50
+ case "alphabet":
51
+ return typedCompareBy("name", alphabetically());
52
+ case "order":
53
+ case "duration":
54
+ case "status":
55
+ return typedCompareBy("statistic", byStatistic());
56
+ default:
57
+ // eslint-disable-next-line no-console
58
+ console.error(`unsupported comparator ${sortBy}`);
59
+ return () => 0;
60
+ }
61
+ };
62
+
63
+ export const leafComparator = (filterOptions: TreeFiltersState): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
64
+ const cmp = leafComparatorByTreeSortBy(filterOptions.sortBy);
65
+ const directional = filterOptions.direction === "asc" ? cmp : reverse(cmp);
66
+ // apply fallback sorting by name
67
+ return andThen([directional, compareBy("name", alphabetically())]);
68
+ };
69
+
70
+ export const groupComparator = (filterOptions: TreeFiltersState): Comparator<DefaultTreeGroup> => {
71
+ const cmp = groupComparatorByTreeSortBy(filterOptions.sortBy);
72
+ const directional = filterOptions.direction === "asc" ? cmp : reverse(cmp);
73
+ // apply fallback sorting by name
74
+ return andThen([directional, compareBy("name", alphabetically())]);
75
+ };
76
+
77
+ export const filterLeaves = (
78
+ leaves: string[] = [],
79
+ leavesById: AwesomeTree["leavesById"],
80
+ filterOptions: TreeFiltersState,
81
+ ) => {
82
+ const filteredLeaves = [...leaves]
83
+ .map((leafId) => leavesById[leafId])
84
+ .filter((leaf: TreeLeaf<AwesomeTreeLeaf>) => isIncluded(leaf, filterOptions));
85
+
86
+ const comparator = leafComparator(filterOptions);
87
+ return filteredLeaves.sort(comparator);
88
+ };
89
+
90
+ /**
91
+ * Fills the given tree from generator and returns recursive tree which includes leaves data instead of their IDs
92
+ * Filters leaves when `filterOptions` property is provided
93
+ * @param payload
94
+ */
95
+ export const createRecursiveTree = (payload: {
96
+ group: AwesomeTreeGroup;
97
+ groupsById: AwesomeTree["groupsById"];
98
+ leavesById: AwesomeTree["leavesById"];
99
+ filterOptions?: TreeFiltersState;
100
+ }): AwesomeRecursiveTree => {
101
+ const { group, groupsById, leavesById, filterOptions } = payload;
102
+ const groupLeaves: string[] = group.leaves ?? [];
103
+
104
+ const leaves = filterLeaves(groupLeaves, leavesById, filterOptions);
105
+ const trees =
106
+ group.groups
107
+ ?.map((groupId) =>
108
+ createRecursiveTree({
109
+ group: groupsById[groupId],
110
+ groupsById,
111
+ leavesById,
112
+ filterOptions,
113
+ }),
114
+ )
115
+ ?.filter((rt) => !isRecursiveTreeEmpty(rt)) ?? [];
116
+
117
+ const statistic: Statistic = emptyStatistic();
118
+ trees.forEach((rt: AwesomeRecursiveTree) => {
119
+ if (rt.statistic) {
120
+ const additional: Statistic = rt.statistic;
121
+ mergeStatistic(statistic, additional);
122
+ }
123
+ });
124
+ leaves.forEach((leaf) => {
125
+ const status: TestStatus = leaf.status;
126
+ incrementStatistic(statistic, status);
127
+ });
128
+
129
+ return {
130
+ ...group,
131
+ statistic,
132
+ leaves,
133
+ trees: trees.sort(groupComparator(filterOptions)),
134
+ };
135
+ };
136
+
137
+ export const isRecursiveTreeEmpty = (tree: AwesomeRecursiveTree): boolean => {
138
+ if (!tree.trees?.length && !tree.leaves?.length) {
139
+ return true;
140
+ }
141
+
142
+ if (tree.leaves?.length) {
143
+ return false;
144
+ }
145
+
146
+ return tree.trees?.every((subTree) => isRecursiveTreeEmpty(subTree));
147
+ };
@@ -0,0 +1,448 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createRecursiveTree, filterLeaves } from "../../src/utils/treeFilters.js";
3
+ import type { AwesomeTestResult } from "../../types.js";
4
+
5
+ describe("utils > treeFilters", () => {
6
+ describe("filterLeaves", () => {
7
+ it("returns the leaves as is when no filter options are provided", () => {
8
+ const baseDate = Date.now();
9
+ const leaves = ["a1", "b2", "c3"];
10
+ const leavesById = {
11
+ a1: {
12
+ name: "a1",
13
+ start: baseDate,
14
+ } as AwesomeTestResult,
15
+ b2: {
16
+ name: "b2",
17
+ start: baseDate + 1000,
18
+ } as AwesomeTestResult,
19
+ c3: {
20
+ name: "c3",
21
+ start: baseDate + 2000,
22
+ } as AwesomeTestResult,
23
+ };
24
+ const result = filterLeaves(leaves, leavesById, {
25
+ query: "",
26
+ status: "total",
27
+ filter: {
28
+ flaky: false,
29
+ retry: false,
30
+ new: false,
31
+ },
32
+ sortBy: "order",
33
+ direction: "asc",
34
+ });
35
+
36
+ expect(result).toEqual([
37
+ expect.objectContaining({ name: "a1" }),
38
+ expect.objectContaining({ name: "b2" }),
39
+ expect.objectContaining({ name: "c3" }),
40
+ ]);
41
+ });
42
+
43
+ it("returns the leaves only matched the status filter", () => {
44
+ const baseDate = Date.now();
45
+ const leaves = ["a1", "b2", "c3"];
46
+ const leavesById = {
47
+ a1: {
48
+ name: "a1",
49
+ status: "passed",
50
+ start: baseDate,
51
+ } as AwesomeTestResult,
52
+ b2: {
53
+ name: "b2",
54
+ status: "failed",
55
+ start: baseDate + 1000,
56
+ } as AwesomeTestResult,
57
+ c3: {
58
+ name: "c3",
59
+ status: "passed",
60
+ start: baseDate + 2000,
61
+ } as AwesomeTestResult,
62
+ };
63
+ const result = filterLeaves(leaves, leavesById, {
64
+ query: "",
65
+ status: "passed",
66
+ filter: {
67
+ flaky: false,
68
+ retry: false,
69
+ new: false,
70
+ },
71
+ sortBy: "order",
72
+ direction: "asc",
73
+ });
74
+
75
+ expect(result).toEqual([expect.objectContaining({ name: "a1" }), expect.objectContaining({ name: "c3" })]);
76
+ });
77
+
78
+ it("returns the flaky leaves", () => {
79
+ const baseDate = Date.now();
80
+ const leaves = ["a1", "b2", "c3"];
81
+ const leavesById = {
82
+ a1: {
83
+ name: "a1",
84
+ start: baseDate,
85
+ flaky: true,
86
+ } as AwesomeTestResult,
87
+ b2: {
88
+ name: "b2",
89
+ start: baseDate + 1000,
90
+ flaky: false,
91
+ } as AwesomeTestResult,
92
+ c3: {
93
+ name: "c3",
94
+ start: baseDate + 2000,
95
+ flaky: true,
96
+ } as AwesomeTestResult,
97
+ };
98
+ const result = filterLeaves(leaves, leavesById, {
99
+ query: "",
100
+ status: "total",
101
+ filter: {
102
+ flaky: true,
103
+ retry: false,
104
+ new: false,
105
+ },
106
+ sortBy: "order",
107
+ direction: "asc",
108
+ });
109
+
110
+ expect(result).toEqual([expect.objectContaining({ name: "a1" }), expect.objectContaining({ name: "c3" })]);
111
+ });
112
+
113
+ it("returns leaves which contains retries", () => {
114
+ const baseDate = Date.now();
115
+ const leaves = ["a1", "b2", "c3"];
116
+ const leavesById = {
117
+ a1: {
118
+ name: "a1",
119
+ start: baseDate,
120
+ retry: true,
121
+ } as AwesomeTestResult,
122
+ b2: {
123
+ name: "b2",
124
+ start: baseDate + 1000,
125
+ retry: false,
126
+ } as AwesomeTestResult,
127
+ c3: {
128
+ name: "c3",
129
+ start: baseDate + 2000,
130
+ retry: false,
131
+ } as AwesomeTestResult,
132
+ };
133
+ const result = filterLeaves(leaves, leavesById, {
134
+ filter: {
135
+ retry: true,
136
+ },
137
+ });
138
+
139
+ expect(result).toEqual([expect.objectContaining({ name: "a1" })]);
140
+ });
141
+
142
+ it("sorts leave by duration in ascending order", () => {
143
+ const leaves = ["a1", "b2", "c3"];
144
+ const leavesById = {
145
+ a1: {
146
+ name: "a1",
147
+ duration: 1000,
148
+ } as AwesomeTestResult,
149
+ b2: {
150
+ name: "b2",
151
+ duration: 2000,
152
+ } as AwesomeTestResult,
153
+ c3: {
154
+ name: "c3",
155
+ duration: 3000,
156
+ } as AwesomeTestResult,
157
+ };
158
+ const result = filterLeaves(leaves, leavesById, {
159
+ direction: "asc",
160
+ sortBy: "duration",
161
+ });
162
+
163
+ expect(result).toEqual([
164
+ expect.objectContaining({ name: "a1" }),
165
+ expect.objectContaining({ name: "b2" }),
166
+ expect.objectContaining({ name: "c3" }),
167
+ ]);
168
+ });
169
+
170
+ it("sorts leave by duration in descending order", () => {
171
+ const leaves = ["a1", "b2", "c3"];
172
+ const leavesById = {
173
+ a1: {
174
+ name: "a1",
175
+ duration: 1000,
176
+ } as AwesomeTestResult,
177
+ b2: {
178
+ name: "b2",
179
+ duration: 2000,
180
+ } as AwesomeTestResult,
181
+ c3: {
182
+ name: "c3",
183
+ duration: 3000,
184
+ } as AwesomeTestResult,
185
+ };
186
+ const result = filterLeaves(leaves, leavesById, {
187
+ direction: "desc",
188
+ sortBy: "duration",
189
+ });
190
+
191
+ expect(result).toEqual([
192
+ expect.objectContaining({ name: "c3" }),
193
+ expect.objectContaining({ name: "b2" }),
194
+ expect.objectContaining({ name: "a1" }),
195
+ ]);
196
+ });
197
+
198
+ it("sorts leaves by title in ascending order", () => {
199
+ const leaves = ["a1", "b2", "c3"];
200
+ const leavesById = {
201
+ a1: {
202
+ name: "a1",
203
+ } as AwesomeTestResult,
204
+ b2: {
205
+ name: "b2",
206
+ } as AwesomeTestResult,
207
+ c3: {
208
+ name: "c3",
209
+ } as AwesomeTestResult,
210
+ };
211
+ const result = filterLeaves(leaves, leavesById, {
212
+ direction: "asc",
213
+ sortBy: "alphabet",
214
+ });
215
+
216
+ expect(result).toEqual([
217
+ expect.objectContaining({ name: "a1" }),
218
+ expect.objectContaining({ name: "b2" }),
219
+ expect.objectContaining({ name: "c3" }),
220
+ ]);
221
+ });
222
+
223
+ it("sorts leaves by title in descending order", () => {
224
+ const leaves = ["a1", "b2", "c3"];
225
+ const leavesById = {
226
+ a1: {
227
+ name: "a1",
228
+ } as AwesomeTestResult,
229
+ b2: {
230
+ name: "b2",
231
+ } as AwesomeTestResult,
232
+ c3: {
233
+ name: "c3",
234
+ } as AwesomeTestResult,
235
+ };
236
+ const result = filterLeaves(leaves, leavesById, {
237
+ direction: "desc",
238
+ sortBy: "alphabet",
239
+ });
240
+
241
+ expect(result).toEqual([
242
+ expect.objectContaining({ name: "c3" }),
243
+ expect.objectContaining({ name: "b2" }),
244
+ expect.objectContaining({ name: "a1" }),
245
+ ]);
246
+ });
247
+
248
+ it("sorts leaves by status in ascending order", () => {
249
+ const leaves = ["a1", "b2", "c3", "d4", "e5"];
250
+ const leavesById = {
251
+ a1: {
252
+ name: "a1",
253
+ status: "passed",
254
+ } as AwesomeTestResult,
255
+ b2: {
256
+ name: "b2",
257
+ status: "failed",
258
+ } as AwesomeTestResult,
259
+ c3: {
260
+ name: "c3",
261
+ status: "broken",
262
+ } as AwesomeTestResult,
263
+ d4: {
264
+ name: "d4",
265
+ status: "unknown",
266
+ } as AwesomeTestResult,
267
+ e5: {
268
+ name: "e5",
269
+ status: "skipped",
270
+ } as AwesomeTestResult,
271
+ };
272
+ const result = filterLeaves(leaves, leavesById, {
273
+ direction: "asc",
274
+ sortBy: "status",
275
+ });
276
+
277
+ expect(result).toEqual([
278
+ expect.objectContaining({ name: "b2" }),
279
+ expect.objectContaining({ name: "c3" }),
280
+ expect.objectContaining({ name: "a1" }),
281
+ expect.objectContaining({ name: "e5" }),
282
+ expect.objectContaining({ name: "d4" }),
283
+ ]);
284
+ });
285
+
286
+ it("sorts leaves by status in descending order", () => {
287
+ const leaves = ["a1", "b2", "c3", "d4", "e5"];
288
+ const leavesById = {
289
+ a1: {
290
+ name: "a1",
291
+ status: "passed",
292
+ } as AwesomeTestResult,
293
+ b2: {
294
+ name: "b2",
295
+ status: "failed",
296
+ } as AwesomeTestResult,
297
+ c3: {
298
+ name: "c3",
299
+ status: "broken",
300
+ } as AwesomeTestResult,
301
+ d4: {
302
+ name: "d4",
303
+ status: "unknown",
304
+ } as AwesomeTestResult,
305
+ e5: {
306
+ name: "e5",
307
+ status: "skipped",
308
+ } as AwesomeTestResult,
309
+ };
310
+ const result = filterLeaves(leaves, leavesById, {
311
+ direction: "desc",
312
+ sortBy: "status",
313
+ });
314
+
315
+ expect(result).toEqual([
316
+ expect.objectContaining({ name: "d4" }),
317
+ expect.objectContaining({ name: "e5" }),
318
+ expect.objectContaining({ name: "a1" }),
319
+ expect.objectContaining({ name: "c3" }),
320
+ expect.objectContaining({ name: "b2" }),
321
+ ]);
322
+ });
323
+
324
+ it("sorts leaves by order number in ascending order", () => {
325
+ const baseDate = Date.now();
326
+ const leaves = ["a1", "b2", "c3"];
327
+ const leavesById = {
328
+ a1: {
329
+ name: "a1",
330
+ start: baseDate + 2000,
331
+ groupOrder: 3,
332
+ } as AwesomeTestResult,
333
+ b2: {
334
+ name: "b2",
335
+ start: baseDate + 1000,
336
+ groupOrder: 2,
337
+ } as AwesomeTestResult,
338
+ c3: {
339
+ name: "c3",
340
+ start: baseDate,
341
+ groupOrder: 1,
342
+ } as AwesomeTestResult,
343
+ };
344
+ const result = filterLeaves(leaves, leavesById, {
345
+ direction: "asc",
346
+ sortBy: "order",
347
+ });
348
+
349
+ expect(result).toEqual([
350
+ expect.objectContaining({ name: "c3" }),
351
+ expect.objectContaining({ name: "b2" }),
352
+ expect.objectContaining({ name: "a1" }),
353
+ ]);
354
+ });
355
+
356
+ it("sorts leaves by order number in descending order", () => {
357
+ const baseDate = Date.now();
358
+ const leaves = ["a1", "b2", "c3"];
359
+ const leavesById = {
360
+ a1: {
361
+ name: "a1",
362
+ start: baseDate + 2000,
363
+ groupOrder: 3,
364
+ } as AwesomeTestResult,
365
+ b2: {
366
+ name: "b2",
367
+ start: baseDate + 1000,
368
+ groupOrder: 2,
369
+ } as AwesomeTestResult,
370
+ c3: {
371
+ name: "c3",
372
+ start: baseDate,
373
+ groupOrder: 1,
374
+ } as AwesomeTestResult,
375
+ };
376
+ const result = filterLeaves(leaves, leavesById, {
377
+ direction: "desc",
378
+ sortBy: "order",
379
+ });
380
+
381
+ expect(result).toEqual([
382
+ expect.objectContaining({ name: "a1" }),
383
+ expect.objectContaining({ name: "b2" }),
384
+ expect.objectContaining({ name: "c3" }),
385
+ ]);
386
+ });
387
+ });
388
+
389
+ describe("createRecursiveTree", () => {
390
+ it("creates recursive tree with filtered and sorted leaves objects", () => {
391
+ const baseDate = Date.now();
392
+ const group = {
393
+ leaves: ["a1"],
394
+ groups: ["a1"],
395
+ };
396
+ const leavesById = {
397
+ a1: {
398
+ name: "a1",
399
+ start: baseDate,
400
+ } as AwesomeTestResult,
401
+ b2: {
402
+ name: "b2",
403
+ start: baseDate + 1000,
404
+ } as AwesomeTestResult,
405
+ c3: {
406
+ name: "c3",
407
+ start: baseDate + 2000,
408
+ } as AwesomeTestResult,
409
+ };
410
+ const groupsById = {
411
+ a1: {
412
+ leaves: ["b2"],
413
+ groups: ["b2"],
414
+ },
415
+ b2: {
416
+ leaves: ["c3"],
417
+ groups: [],
418
+ },
419
+ };
420
+ const result = createRecursiveTree({
421
+ group,
422
+ leavesById,
423
+ groupsById,
424
+ filterOptions: {
425
+ sortBy: "alphabet",
426
+ direction: "asc",
427
+ },
428
+ });
429
+
430
+ expect(result).toEqual(
431
+ expect.objectContaining({
432
+ leaves: [expect.objectContaining({ name: "a1" })],
433
+ trees: [
434
+ expect.objectContaining({
435
+ leaves: [expect.objectContaining({ name: "b2" })],
436
+ trees: [
437
+ expect.objectContaining({
438
+ leaves: [expect.objectContaining({ name: "c3" })],
439
+ trees: [],
440
+ }),
441
+ ],
442
+ }),
443
+ ],
444
+ }),
445
+ );
446
+ });
447
+ });
448
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": "./",
4
+ "paths": {
5
+ "@/*": ["src/*"]
6
+ },
7
+ "jsx": "preserve",
8
+ "jsxFactory": "h",
9
+ "jsxFragmentFactory": "Fragment",
10
+ "jsxImportSource": "preact",
11
+ "target": "ESNext",
12
+ "module": "ESNext",
13
+ "moduleResolution": "node",
14
+ "allowSyntheticDefaultImports": true,
15
+ "useUnknownInCatchVariables": false,
16
+ "noEmit": true,
17
+ "noImplicitAny": true,
18
+ "resolveJsonModule": true,
19
+ "esModuleInterop": true,
20
+ "lib": ["ES2019", "dom"],
21
+ // node types should not be used in web-commons
22
+ "types": [],
23
+ "skipLibCheck": true
24
+ },
25
+ "include": ["src"],
26
+ "exclude": ["node_modules", "dist"]
27
+ }