@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
package/src/locales/pl.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Kopiuj e-mail",
|
|
152
152
|
"attempt": "Próba {{attempt}} z {{total}}",
|
|
153
153
|
"at": "w",
|
|
154
|
+
"generated": "Wygenerowano",
|
|
154
155
|
"variables": "Zmienne",
|
|
155
156
|
"openPwTrace": "Otwórz Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "Przeglądarka zablokowała otwarcie Playwright Trace Viewer.",
|
package/src/locales/pt.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Copiar e-mail",
|
|
152
152
|
"attempt": "Tentativa {{attempt}} de {{total}}",
|
|
153
153
|
"at": "em",
|
|
154
|
+
"generated": "Gerado",
|
|
154
155
|
"variables": "Variáveis",
|
|
155
156
|
"openPwTrace": "Abrir Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "O navegador bloqueou a abertura do Playwright Trace Viewer.",
|
package/src/locales/ru.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Скопировать 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/sv.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Kopiera e-post",
|
|
152
152
|
"attempt": "Försök {{attempt}} av {{total}}",
|
|
153
153
|
"at": "vid",
|
|
154
|
+
"generated": "Genererad",
|
|
154
155
|
"variables": "Variabler",
|
|
155
156
|
"openPwTrace": "Öppna Playwright Trace",
|
|
156
157
|
"pwTracePopupBlocked": "Webbläsaren blockerade öppning av Playwright Trace Viewer.",
|
package/src/locales/tr.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "E-postayı kopyala",
|
|
152
152
|
"attempt": "Deneme {{attempt}} / {{total}}",
|
|
153
153
|
"at": "tarihinde",
|
|
154
|
+
"generated": "Oluşturuldu",
|
|
154
155
|
"variables": "Değişkenler",
|
|
155
156
|
"openPwTrace": "Playwright Trace Aç",
|
|
156
157
|
"pwTracePopupBlocked": "Tarayıcı Playwright Trace Viewer’ın açılmasını engelledi.",
|
package/src/locales/uk.json
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"copy-email": "Скопіювати 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/zh-TW.json
CHANGED
package/src/locales/zh.json
CHANGED
package/src/stores/locale.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { computed, signal } from "@preact/signals";
|
|
|
10
10
|
import i18next, { type TOptions } from "i18next";
|
|
11
11
|
import type { AwesomeReportOptions } from "types";
|
|
12
12
|
|
|
13
|
+
import { ensureAtSeparator } from "@/utils/atSeparator";
|
|
14
|
+
|
|
13
15
|
const namespaces = [
|
|
14
16
|
"empty",
|
|
15
17
|
"execution",
|
|
@@ -112,7 +114,7 @@ export const waitForI18next = i18next
|
|
|
112
114
|
if (override?.includeAtSeparator === false || override?.stripComma) {
|
|
113
115
|
return formatted.replace(",", "");
|
|
114
116
|
}
|
|
115
|
-
return formatted
|
|
117
|
+
return ensureAtSeparator(formatted, i18next.t("ui:at"));
|
|
116
118
|
},
|
|
117
119
|
);
|
|
118
120
|
i18next.services.formatter.add(
|
|
@@ -133,7 +135,7 @@ export const waitForI18next = i18next
|
|
|
133
135
|
if (override?.includeAtSeparator === false || override?.stripComma) {
|
|
134
136
|
return formatted.replace(",", "");
|
|
135
137
|
}
|
|
136
|
-
return formatted
|
|
138
|
+
return ensureAtSeparator(formatted, i18next.t("ui:at"));
|
|
137
139
|
},
|
|
138
140
|
);
|
|
139
141
|
i18next.services.formatter.add("format_duration", (value: number) => {
|
package/src/stores/treeSort.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { getParamValue, hasParam, setParams } from "@allurereport/web-commons";
|
|
1
|
+
import { getParamValue, getReportOptions, hasParam, setParams } from "@allurereport/web-commons";
|
|
2
2
|
import { computed, effect, signal } from "@preact/signals";
|
|
3
3
|
|
|
4
|
+
import type { AwesomeReportOptions } from "../../types.js";
|
|
5
|
+
|
|
4
6
|
export type SortByDirection = "asc" | "desc";
|
|
5
7
|
export type SortByField = "order" | "duration" | "status" | "name";
|
|
6
8
|
export type SortBy = `${SortByField},${SortByDirection}`;
|
|
@@ -34,6 +36,10 @@ const getInitialSortBy = (): SortBy => {
|
|
|
34
36
|
if (stored && validateSortBy(stored.toLowerCase())) {
|
|
35
37
|
return stored.toLowerCase() as SortBy;
|
|
36
38
|
}
|
|
39
|
+
const { defaultSortBy } = getReportOptions<AwesomeReportOptions>() ?? {};
|
|
40
|
+
if (defaultSortBy && validateSortBy(defaultSortBy.toLowerCase())) {
|
|
41
|
+
return defaultSortBy.toLowerCase() as SortBy;
|
|
42
|
+
}
|
|
37
43
|
return DEFAULT_SORT_BY;
|
|
38
44
|
};
|
|
39
45
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// border-top on the white pane card (visible above header/content; inset shadow is covered by children).
|
|
2
2
|
@mixin split-pane-indicator {
|
|
3
|
-
border-top:
|
|
3
|
+
border-top: 2px solid transparent;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
@mixin split-pane-indicator-active {
|
|
7
|
-
border-top-color: var(--
|
|
7
|
+
border-top-color: var(--color-intent-primary-text);
|
|
8
8
|
}
|
package/src/utils/time.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getLocaleDateTimeOverride } from "@allurereport/web-commons";
|
|
2
2
|
|
|
3
3
|
import { currentLocale, currentLocaleIso, useI18n } from "@/stores/locale";
|
|
4
|
+
import { ensureAtSeparator } from "@/utils/atSeparator";
|
|
4
5
|
|
|
5
6
|
const defaultOptions: Intl.DateTimeFormatOptions = {
|
|
6
7
|
month: "numeric",
|
|
@@ -29,5 +30,5 @@ export const timestampToDate = (timestamp: number, options = defaultOptions) =>
|
|
|
29
30
|
return formatted.replace(",", "");
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
return formatted
|
|
33
|
+
return ensureAtSeparator(formatted, t("at"));
|
|
33
34
|
};
|
package/src/utils/treeFilters.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Comparator,
|
|
1
|
+
import type { Comparator, Statistic, TestStatus, TreeLeaf } from "@allurereport/core-api";
|
|
2
2
|
import {
|
|
3
3
|
alphabetically,
|
|
4
4
|
andThen,
|
|
@@ -38,16 +38,18 @@ const leafComparatorByTreeSortBy = (sortBy: SortBy = "status,asc"): Comparator<T
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
const groupComparatorByTreeSortBy = (sortBy: SortBy = "status,asc"): Comparator<
|
|
42
|
-
const typedCompareBy = compareBy<
|
|
41
|
+
const groupComparatorByTreeSortBy = (sortBy: SortBy = "status,asc"): Comparator<AwesomeRecursiveTree> => {
|
|
42
|
+
const typedCompareBy = compareBy<AwesomeRecursiveTree>;
|
|
43
43
|
switch (sortBy) {
|
|
44
44
|
case "name,desc":
|
|
45
45
|
case "name,asc":
|
|
46
46
|
return typedCompareBy("name", alphabetically());
|
|
47
47
|
case "order,desc":
|
|
48
48
|
case "order,asc":
|
|
49
|
+
return typedCompareBy("groupOrder", ordinal());
|
|
49
50
|
case "duration,desc":
|
|
50
51
|
case "duration,asc":
|
|
52
|
+
return typedCompareBy("duration", ordinal());
|
|
51
53
|
case "status,desc":
|
|
52
54
|
case "status,asc":
|
|
53
55
|
return typedCompareBy("statistic", byStatistic());
|
|
@@ -76,7 +78,7 @@ export const leafComparator = (sortBy: SortBy = "status,asc"): Comparator<TreeLe
|
|
|
76
78
|
return withDirection(cmp, sortBy);
|
|
77
79
|
};
|
|
78
80
|
|
|
79
|
-
export const groupComparator = (sortBy: SortBy = "status,asc"): Comparator<
|
|
81
|
+
export const groupComparator = (sortBy: SortBy = "status,asc"): Comparator<AwesomeRecursiveTree> => {
|
|
80
82
|
const cmp = groupComparatorByTreeSortBy(sortBy);
|
|
81
83
|
|
|
82
84
|
return withDirection(cmp, sortBy);
|
|
@@ -150,11 +152,20 @@ export const createRecursiveTree = (payload: {
|
|
|
150
152
|
incrementStatistic(statistic, status);
|
|
151
153
|
});
|
|
152
154
|
|
|
155
|
+
const duration =
|
|
156
|
+
leaves.reduce((acc, leaf) => acc + (leaf.duration ?? 0), 0) + trees.reduce((acc, rt) => acc + rt.duration, 0);
|
|
157
|
+
|
|
158
|
+
const leafMinOrder = leaves.reduce((acc, leaf) => Math.min(acc, leaf.groupOrder ?? Infinity), Infinity);
|
|
159
|
+
const treeMinOrder = trees.reduce((acc, rt) => Math.min(acc, rt.groupOrder), Infinity);
|
|
160
|
+
const groupOrder = Math.min(leafMinOrder, treeMinOrder);
|
|
161
|
+
|
|
153
162
|
return {
|
|
154
163
|
...group,
|
|
155
164
|
statistic,
|
|
156
165
|
leaves,
|
|
157
166
|
trees: trees.sort(groupComparator(sortBy)),
|
|
167
|
+
duration,
|
|
168
|
+
groupOrder: isFinite(groupOrder) ? groupOrder : 0,
|
|
158
169
|
};
|
|
159
170
|
};
|
|
160
171
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/preact";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { Footer } from "@/components/Footer";
|
|
5
|
+
|
|
6
|
+
vi.mock("@/components/Footer/FooterLogo", () => ({
|
|
7
|
+
FooterLogo: () => <div data-testid="footer-logo" />,
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
vi.mock("@allurereport/web-components", () => ({
|
|
11
|
+
LanguagePicker: () => <div data-testid="footer-language-picker" />,
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock("@/components/Footer/FooterVersion", () => ({
|
|
15
|
+
FooterVersion: () => <div data-testid="footer-version">Generated May 10, 2026 Ver: 3.8.2</div>,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
describe("components > Footer", () => {
|
|
19
|
+
it("should render language picker near generated time and version", () => {
|
|
20
|
+
render(<Footer />);
|
|
21
|
+
|
|
22
|
+
expect(screen.getByTestId("footer-logo")).toBeInTheDocument();
|
|
23
|
+
expect(screen.getByTestId("footer-language-picker")).toBeInTheDocument();
|
|
24
|
+
expect(screen.getByTestId("footer-version")).toHaveTextContent("Generated");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -197,4 +197,52 @@ describe("components > Header > CiInfo", () => {
|
|
|
197
197
|
|
|
198
198
|
expect(screen.getByRole("link")).toHaveTextContent(fixtures.jobRunName);
|
|
199
199
|
});
|
|
200
|
+
|
|
201
|
+
it("should not render executor metadata in the header", () => {
|
|
202
|
+
(getReportOptions as Mock).mockReturnValueOnce({
|
|
203
|
+
executor: {
|
|
204
|
+
name: "TeamCity",
|
|
205
|
+
type: "teamcity",
|
|
206
|
+
buildName: "Wrike #123",
|
|
207
|
+
buildUrl: "https://teamcity.example/build/123",
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
render(<CiInfo />);
|
|
212
|
+
|
|
213
|
+
expect(screen.queryByRole("link")).not.toBeInTheDocument();
|
|
214
|
+
expect(screen.queryByText("TeamCity · Wrike #123")).not.toBeInTheDocument();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("should render ci label as plain text when ci has a name but no link", () => {
|
|
218
|
+
(getReportOptions as Mock).mockReturnValueOnce({
|
|
219
|
+
ci: {
|
|
220
|
+
jobName: "Nightly Build",
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
render(<CiInfo />);
|
|
225
|
+
|
|
226
|
+
expect(screen.queryByRole("link")).not.toBeInTheDocument();
|
|
227
|
+
expect(screen.getByText("Nightly Build")).toBeInTheDocument();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("should ignore executor metadata when ci has no link", () => {
|
|
231
|
+
(getReportOptions as Mock).mockReturnValueOnce({
|
|
232
|
+
ci: {
|
|
233
|
+
jobName: "Nightly Build",
|
|
234
|
+
},
|
|
235
|
+
executor: {
|
|
236
|
+
name: "TeamCity",
|
|
237
|
+
buildName: "Wrike #123",
|
|
238
|
+
buildUrl: "https://teamcity.example/build/123",
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
render(<CiInfo />);
|
|
243
|
+
|
|
244
|
+
expect(screen.queryByRole("link")).not.toBeInTheDocument();
|
|
245
|
+
expect(screen.getByText("Nightly Build")).toBeInTheDocument();
|
|
246
|
+
expect(screen.queryByText("TeamCity · Wrike #123")).not.toBeInTheDocument();
|
|
247
|
+
});
|
|
200
248
|
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/preact";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { HeaderControls } from "@/components/HeaderControls";
|
|
5
|
+
|
|
6
|
+
vi.mock("@/components/EnvironmentPicker", () => ({
|
|
7
|
+
EnvironmentPicker: () => <div data-testid="environment-picker" />,
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
vi.mock("@/components/ToggleLayout", () => ({
|
|
11
|
+
default: () => <div data-testid="toggle-layout" />,
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock("@allurereport/web-components", () => ({
|
|
15
|
+
ThemeButton: () => <button data-testid="theme-button" type="button" />,
|
|
16
|
+
LanguagePicker: () => <button data-testid="language-picker" type="button" />,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
describe("components > HeaderControls", () => {
|
|
20
|
+
it("should keep frequent controls in header and omit language picker", () => {
|
|
21
|
+
render(<HeaderControls />);
|
|
22
|
+
|
|
23
|
+
expect(screen.getByTestId("environment-picker")).toBeInTheDocument();
|
|
24
|
+
expect(screen.getByTestId("toggle-layout")).toBeInTheDocument();
|
|
25
|
+
expect(screen.getByTestId("theme-button")).toBeInTheDocument();
|
|
26
|
+
expect(screen.queryByTestId("language-picker")).not.toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { getReportOptions } from "@allurereport/web-commons";
|
|
2
|
+
import { render, screen } from "@testing-library/preact";
|
|
3
|
+
import { type Mock, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { ReportHeader } from "@/components/ReportHeader";
|
|
6
|
+
|
|
7
|
+
vi.mock("@allurereport/web-commons", async (importOriginal) => ({
|
|
8
|
+
...(await importOriginal()),
|
|
9
|
+
getReportOptions: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock("@allurereport/web-components", () => ({
|
|
13
|
+
Heading: (props: { children: string }) => <h2>{props.children}</h2>,
|
|
14
|
+
Loadable: (props: { renderData: (data: unknown) => unknown }) => props.renderData({}),
|
|
15
|
+
Text: (props: { "children": unknown; "data-testid"?: string }) => (
|
|
16
|
+
<span data-testid={props["data-testid"]}>{props.children}</span>
|
|
17
|
+
),
|
|
18
|
+
TooltipWrapper: (props: { children: unknown }) => props.children,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
vi.mock("@/components/ReportHeader/ReportHeaderLogo", () => ({
|
|
22
|
+
ReportHeaderLogo: () => <div data-testid="report-logo" />,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
vi.mock("@/components/ReportHeader/ReportHeaderPie", () => ({
|
|
26
|
+
ReportHeaderPie: () => <div data-testid="report-pie" />,
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
vi.mock("@/components/TestResult/TrStatus", () => ({
|
|
30
|
+
TrStatus: () => <div data-testid="tr-status" />,
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
vi.mock("@/stores", () => ({
|
|
34
|
+
useI18n: () => ({
|
|
35
|
+
t: (key: string, params: Record<string, unknown>) => `${key}: ${params.formattedCreatedAt}`,
|
|
36
|
+
}),
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
vi.mock("@/utils/time", () => ({
|
|
40
|
+
timestampToDate: (value: number, options?: Intl.DateTimeFormatOptions) =>
|
|
41
|
+
`${options?.month === "long" ? "long" : "default"}:${value}`,
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
vi.clearAllMocks();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("components > ReportHeader", () => {
|
|
49
|
+
it("should render launch start time and duration when run summary is available", () => {
|
|
50
|
+
(getReportOptions as Mock).mockReturnValue({
|
|
51
|
+
reportName: "Wrike report",
|
|
52
|
+
createdAt: 42,
|
|
53
|
+
runSummary: {
|
|
54
|
+
start: 1000,
|
|
55
|
+
stop: 2500,
|
|
56
|
+
duration: 1500,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
render(<ReportHeader />);
|
|
61
|
+
|
|
62
|
+
expect(screen.getByTestId("report-data")).toHaveTextContent("long:1000");
|
|
63
|
+
expect(screen.getByTestId("report-data")).not.toHaveTextContent("long:2500");
|
|
64
|
+
expect(screen.getByTestId("report-data")).not.toHaveTextContent("long:42");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should fall back to generated time when run summary is missing", () => {
|
|
68
|
+
(getReportOptions as Mock).mockReturnValue({
|
|
69
|
+
reportName: "Wrike report",
|
|
70
|
+
createdAt: 10,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
render(<ReportHeader />);
|
|
74
|
+
|
|
75
|
+
expect(screen.getByTestId("report-data")).toHaveTextContent("long:10");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { getReportOptions } from "@allurereport/web-commons";
|
|
2
|
+
import { cleanup, render, screen } from "@testing-library/preact";
|
|
3
|
+
import { type Mock, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { ReportMetadata } from "@/components/ReportMetadata";
|
|
6
|
+
|
|
7
|
+
vi.mock("@allurereport/web-commons", async (importOriginal) => ({
|
|
8
|
+
...(await importOriginal()),
|
|
9
|
+
getReportOptions: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock("@allurereport/web-components", () => {
|
|
13
|
+
const Menu = Object.assign(
|
|
14
|
+
(props: { children: unknown; menuTrigger: (props: { onClick: () => void }) => unknown }) => (
|
|
15
|
+
<>
|
|
16
|
+
{props.menuTrigger({ onClick: vi.fn() })}
|
|
17
|
+
{props.children}
|
|
18
|
+
</>
|
|
19
|
+
),
|
|
20
|
+
{
|
|
21
|
+
Section: (props: { children: unknown }) => <>{props.children}</>,
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
ArrowButton: () => <span />,
|
|
27
|
+
Button: (props: { text?: string; onClick?: () => void }) => <button onClick={props.onClick}>{props.text}</button>,
|
|
28
|
+
ButtonLink: (props: { href: string; text?: string }) => <a href={props.href}>{props.text}</a>,
|
|
29
|
+
Counter: (props: { count: number }) => <span>{props.count}</span>,
|
|
30
|
+
Loadable: (props: {
|
|
31
|
+
source: { value?: { data?: unknown } };
|
|
32
|
+
transformData?: (data: unknown) => unknown;
|
|
33
|
+
renderData: (data: unknown) => unknown;
|
|
34
|
+
}) =>
|
|
35
|
+
props.renderData(props.transformData ? props.transformData(props.source.value?.data) : props.source.value?.data),
|
|
36
|
+
Menu,
|
|
37
|
+
SvgIcon: () => <span />,
|
|
38
|
+
Text: (props: { children: unknown }) => <span>{props.children}</span>,
|
|
39
|
+
TooltipWrapper: (props: { children: unknown }) => props.children,
|
|
40
|
+
allureIcons: {
|
|
41
|
+
lineGeneralCopy3: "copy",
|
|
42
|
+
lineGeneralLinkExternal: "external",
|
|
43
|
+
},
|
|
44
|
+
useElementTruncation: () => ({ ref: { current: null }, isTruncated: false }),
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
vi.mock("@/stores", () => ({
|
|
49
|
+
reportStatsStore: { value: { data: undefined } },
|
|
50
|
+
statsByEnvStore: { value: { data: {} } },
|
|
51
|
+
useI18n: () => ({
|
|
52
|
+
t: (key: string) => key,
|
|
53
|
+
}),
|
|
54
|
+
}));
|
|
55
|
+
|
|
56
|
+
vi.mock("@/stores/env", () => ({
|
|
57
|
+
currentEnvironment: { value: undefined },
|
|
58
|
+
}));
|
|
59
|
+
|
|
60
|
+
vi.mock("@/stores/envInfo", () => ({
|
|
61
|
+
envInfoStore: { value: { data: [] } },
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
vi.mock("@/stores/tree", () => ({
|
|
65
|
+
collapsedTrees: { value: new Set() },
|
|
66
|
+
toggleTree: vi.fn(),
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
vi.mock("@/stores/variables", () => ({
|
|
70
|
+
fetchVariables: vi.fn(),
|
|
71
|
+
variables: { value: { data: { default: {} } } },
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
vi.clearAllMocks();
|
|
76
|
+
cleanup();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("components > ReportMetadata", () => {
|
|
80
|
+
it("should render executor metadata as a clickable build link", () => {
|
|
81
|
+
(getReportOptions as Mock).mockReturnValue({
|
|
82
|
+
executor: {
|
|
83
|
+
name: "TeamCity",
|
|
84
|
+
buildName: "Wrike #123",
|
|
85
|
+
url: "https://teamcity.example",
|
|
86
|
+
reportUrl: "https://teamcity.example/report/123",
|
|
87
|
+
buildUrl: "https://teamcity.example/build/123",
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
render(<ReportMetadata />);
|
|
92
|
+
|
|
93
|
+
expect(screen.getByText("executor")).toBeInTheDocument();
|
|
94
|
+
expect(screen.getByRole("link", { name: "TeamCity · Wrike #123" })).toHaveAttribute(
|
|
95
|
+
"href",
|
|
96
|
+
"https://teamcity.example/build/123",
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("should fall back to report url when executor build url is missing", () => {
|
|
101
|
+
(getReportOptions as Mock).mockReturnValue({
|
|
102
|
+
executor: {
|
|
103
|
+
name: "TeamCity",
|
|
104
|
+
buildName: "Wrike #123",
|
|
105
|
+
reportUrl: "https://teamcity.example/report/123",
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
render(<ReportMetadata />);
|
|
110
|
+
|
|
111
|
+
expect(screen.getByRole("link", { name: "TeamCity · Wrike #123" })).toHaveAttribute(
|
|
112
|
+
"href",
|
|
113
|
+
"https://teamcity.example/report/123",
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should render executor metadata as plain text when url is unsafe", () => {
|
|
118
|
+
(getReportOptions as Mock).mockReturnValue({
|
|
119
|
+
executor: {
|
|
120
|
+
name: "TeamCity",
|
|
121
|
+
buildName: "Wrike #123",
|
|
122
|
+
buildUrl: "javascript:alert(1)",
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
render(<ReportMetadata />);
|
|
127
|
+
|
|
128
|
+
expect(screen.queryByRole("link", { name: "TeamCity · Wrike #123" })).not.toBeInTheDocument();
|
|
129
|
+
expect(screen.getByTestId("metadata-item")).toHaveTextContent("TeamCity · Wrike #123");
|
|
130
|
+
});
|
|
131
|
+
});
|