@allurereport/web-summary 3.0.0-beta.11
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/.babelrc.js +22 -0
- package/.eslintrc.cjs +18 -0
- package/README.md +0 -0
- package/dist/app-af9981fc.js +2 -0
- package/dist/app-af9981fc.js.LICENSE.txt +8 -0
- package/dist/manifest.json +3 -0
- package/package.json +88 -0
- package/postcss.config.js +5 -0
- package/src/assets/scss/_common.scss +143 -0
- package/src/assets/scss/day.scss +51 -0
- package/src/assets/scss/fonts.scss +3 -0
- package/src/assets/scss/index.scss +7 -0
- package/src/assets/scss/night.scss +61 -0
- package/src/assets/scss/palette.scss +393 -0
- package/src/assets/scss/theme.scss +119 -0
- package/src/assets/scss/vars.scss +8 -0
- package/src/components/EmptyPlaceholder/index.tsx +24 -0
- package/src/components/EmptyPlaceholder/styles.scss +25 -0
- package/src/components/Footer/index.tsx +21 -0
- package/src/components/Footer/styles.scss +23 -0
- package/src/components/Header/index.tsx +15 -0
- package/src/components/Header/styles.scss +8 -0
- package/src/components/LanguagePicker/index.tsx +40 -0
- package/src/components/MetadataRow/index.tsx +20 -0
- package/src/components/MetadataRow/styles.scss +9 -0
- package/src/components/ReportCard/index.tsx +70 -0
- package/src/components/ReportCard/styles.scss +49 -0
- package/src/components/ThemeButton/index.tsx +20 -0
- package/src/i18n/constants.ts +124 -0
- package/src/i18n/locales/az.json +14 -0
- package/src/i18n/locales/de.json +14 -0
- package/src/i18n/locales/en.json +14 -0
- package/src/i18n/locales/es.json +14 -0
- package/src/i18n/locales/fr.json +14 -0
- package/src/i18n/locales/he.json +14 -0
- package/src/i18n/locales/hy.json +13 -0
- package/src/i18n/locales/it.json +14 -0
- package/src/i18n/locales/ja.json +14 -0
- package/src/i18n/locales/ka.json +14 -0
- package/src/i18n/locales/kr.json +14 -0
- package/src/i18n/locales/nl.json +14 -0
- package/src/i18n/locales/pl.json +14 -0
- package/src/i18n/locales/pt.json +14 -0
- package/src/i18n/locales/ru.json +14 -0
- package/src/i18n/locales/sv.json +14 -0
- package/src/i18n/locales/tr.json +14 -0
- package/src/i18n/locales/zh.json +14 -0
- package/src/index.html +89 -0
- package/src/index.tsx +59 -0
- package/src/stores/index.ts +2 -0
- package/src/stores/locale.ts +54 -0
- package/src/stores/theme.ts +29 -0
- package/src/styles.scss +50 -0
- package/src/types/globals.d.ts +13 -0
- package/src/types/window.d.ts +10 -0
- package/tsconfig.json +27 -0
- package/types.d.ts +99 -0
- package/webpack.config.js +109 -0
package/src/index.tsx
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import "@allurereport/web-components/index.css";
|
|
2
|
+
import { render } from "preact";
|
|
3
|
+
import { useEffect, useState } from "preact/hooks";
|
|
4
|
+
import "@/assets/scss/index.scss";
|
|
5
|
+
import { EmptyPlaceholder } from "@/components/EmptyPlaceholder";
|
|
6
|
+
import { Footer } from "@/components/Footer";
|
|
7
|
+
import { Header } from "@/components/Header";
|
|
8
|
+
import { ReportCard } from "@/components/ReportCard";
|
|
9
|
+
import { getLocale, getTheme, useI18n, waitForI18next } from "@/stores";
|
|
10
|
+
import * as styles from "./styles.scss";
|
|
11
|
+
|
|
12
|
+
const App = () => {
|
|
13
|
+
const [loaded, setLoaded] = useState(false);
|
|
14
|
+
const summaries = window.reportSummaries;
|
|
15
|
+
const { t } = useI18n("empty");
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
getLocale();
|
|
19
|
+
getTheme();
|
|
20
|
+
waitForI18next.then(() => {
|
|
21
|
+
setLoaded(true);
|
|
22
|
+
});
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
if (!loaded) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className={styles.container}>
|
|
31
|
+
<Header />
|
|
32
|
+
<main>
|
|
33
|
+
{!summaries.length && <EmptyPlaceholder label={t("no-reports")} />}
|
|
34
|
+
{!!summaries.length && (
|
|
35
|
+
<ul className={styles["summary-showcase"]}>
|
|
36
|
+
{summaries.map((summary: any) => {
|
|
37
|
+
return (
|
|
38
|
+
<li key={summary.output}>
|
|
39
|
+
<ReportCard
|
|
40
|
+
href={summary.href}
|
|
41
|
+
name={summary.name}
|
|
42
|
+
status={summary.status}
|
|
43
|
+
stats={summary.stats}
|
|
44
|
+
duration={summary.duration}
|
|
45
|
+
/>
|
|
46
|
+
</li>
|
|
47
|
+
);
|
|
48
|
+
})}
|
|
49
|
+
</ul>
|
|
50
|
+
)}
|
|
51
|
+
</main>
|
|
52
|
+
<Footer className={styles.footer} />
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const rootElement = document.getElementById("app");
|
|
58
|
+
|
|
59
|
+
render(<App />, rootElement);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { computed, signal } from "@preact/signals";
|
|
2
|
+
import i18next, { type TOptions } from "i18next";
|
|
3
|
+
import { DEFAULT_LOCALE, LANG_LOCALE, type LangLocale } from "@/i18n/constants";
|
|
4
|
+
|
|
5
|
+
const namespaces = ["empty", "summary"];
|
|
6
|
+
|
|
7
|
+
export const currentLocale = signal<LangLocale>("en" as LangLocale);
|
|
8
|
+
export const currentLocaleIso = computed(() => LANG_LOCALE[currentLocale.value]?.iso ?? LANG_LOCALE.en.iso);
|
|
9
|
+
export const currentLocaleIsRTL = computed(() => ["ar", "he", "fa"].includes(currentLocale.value));
|
|
10
|
+
|
|
11
|
+
export const getLocale = async () => {
|
|
12
|
+
const locale = localStorage.getItem("currentLocale") || DEFAULT_LOCALE;
|
|
13
|
+
|
|
14
|
+
await setLocale(locale as LangLocale);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const waitForI18next = i18next
|
|
18
|
+
.use({
|
|
19
|
+
type: "backend",
|
|
20
|
+
read: async (
|
|
21
|
+
language: LangLocale,
|
|
22
|
+
namespace: string,
|
|
23
|
+
callback: (errorValue: unknown, translations: null) => void,
|
|
24
|
+
) => {
|
|
25
|
+
await import(`@/i18n/locales/${language}.json`)
|
|
26
|
+
.then((resources: Record<string, null>) => {
|
|
27
|
+
callback(null, resources[namespace]);
|
|
28
|
+
})
|
|
29
|
+
.catch((error) => {
|
|
30
|
+
callback(error, null);
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
.init({
|
|
35
|
+
lng: currentLocale.value,
|
|
36
|
+
fallbackLng: "en",
|
|
37
|
+
ns: namespaces,
|
|
38
|
+
interpolation: { escapeValue: false },
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const useI18n = (namespace?: string) => {
|
|
42
|
+
const t = computed(() => (key: string, options?: TOptions) => i18next.t(key, { ns: namespace, ...options }));
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
t: t.value,
|
|
46
|
+
currentLocale: currentLocale.value,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const setLocale = async (locale: LangLocale) => {
|
|
51
|
+
await i18next.changeLanguage(locale as string);
|
|
52
|
+
localStorage.setItem("currentLocale", locale as string);
|
|
53
|
+
currentLocale.value = locale;
|
|
54
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { signal } from "@preact/signals";
|
|
2
|
+
|
|
3
|
+
type Theme = "light" | "dark";
|
|
4
|
+
|
|
5
|
+
export const themeStore = signal<Theme>("light");
|
|
6
|
+
|
|
7
|
+
export const setTheme = (newTheme: Theme): void => {
|
|
8
|
+
themeStore.value = newTheme;
|
|
9
|
+
document.documentElement.setAttribute("data-theme", newTheme);
|
|
10
|
+
window.localStorage.setItem("theme", newTheme);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const toggleTheme = () => {
|
|
14
|
+
setTheme(themeStore.value === "light" ? "dark" : "light");
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getTheme = () => {
|
|
18
|
+
const themeFromLS = window.localStorage.getItem("theme") as Theme | null;
|
|
19
|
+
|
|
20
|
+
if (themeFromLS) {
|
|
21
|
+
setTheme(themeFromLS);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
26
|
+
const initialTheme = prefersDarkScheme ? "dark" : "light";
|
|
27
|
+
|
|
28
|
+
setTheme(initialTheme);
|
|
29
|
+
};
|
package/src/styles.scss
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--showcase-width: 940px;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.container {
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
gap: 16px;
|
|
9
|
+
padding: 16px 0 24px 0;
|
|
10
|
+
max-width: var(--showcase-width);
|
|
11
|
+
margin: 0 auto;
|
|
12
|
+
min-height: 100vh;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.summary-showcase {
|
|
16
|
+
display: grid;
|
|
17
|
+
grid-template-columns: repeat(2, 1fr);
|
|
18
|
+
gap: 8px;
|
|
19
|
+
margin-bottom: 40px;
|
|
20
|
+
//max-width: var(--showcase-width);
|
|
21
|
+
//margin: 0 auto;
|
|
22
|
+
//padding: 40px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.summary-card {
|
|
26
|
+
display: block;
|
|
27
|
+
padding: 16px;
|
|
28
|
+
height: 100%;
|
|
29
|
+
text-decoration: none;
|
|
30
|
+
box-shadow: var(--shadow-small);
|
|
31
|
+
background: var(--bg-base-primary);
|
|
32
|
+
border-radius: 12px;
|
|
33
|
+
|
|
34
|
+
&:hover {
|
|
35
|
+
box-shadow: none;
|
|
36
|
+
transition: box-shadow 0.2s;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.summary-card-title {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: flex-start;
|
|
43
|
+
gap: 0 4px;
|
|
44
|
+
color: var(--on-text-secondary);
|
|
45
|
+
margin-top: 12px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.footer {
|
|
49
|
+
margin-top: auto;
|
|
50
|
+
}
|
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
|
+
}
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AttachmentTestStepResult,
|
|
3
|
+
DefaultTreeGroup,
|
|
4
|
+
HistoryTestResult,
|
|
5
|
+
TestFixtureResult,
|
|
6
|
+
TestResult,
|
|
7
|
+
TestStatus,
|
|
8
|
+
TestStepResult,
|
|
9
|
+
TreeData,
|
|
10
|
+
WithChildren,
|
|
11
|
+
} from "@allurereport/core-api";
|
|
12
|
+
|
|
13
|
+
export type Layout = "base" | "split";
|
|
14
|
+
|
|
15
|
+
export type AwesomeReportOptions = {
|
|
16
|
+
allureVersion: string;
|
|
17
|
+
reportName?: string;
|
|
18
|
+
logo?: string;
|
|
19
|
+
theme?: "light" | "dark";
|
|
20
|
+
groupBy?: string[];
|
|
21
|
+
reportLanguage?: "en" | "ru";
|
|
22
|
+
createdAt: number;
|
|
23
|
+
reportUuid: string;
|
|
24
|
+
layout?: Layout;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type AwesomeFixtureResult = Omit<
|
|
28
|
+
TestFixtureResult,
|
|
29
|
+
"testResultIds" | "start" | "stop" | "sourceMetadata" | "steps"
|
|
30
|
+
> & {
|
|
31
|
+
steps: AwesomeTestStepResult[];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type AwesomeStatus = TestStatus | "total";
|
|
35
|
+
|
|
36
|
+
export type AwesomeTestStepResult = TestStepResult;
|
|
37
|
+
|
|
38
|
+
type AwesomeBreadcrumbItem = string[] | string[][];
|
|
39
|
+
|
|
40
|
+
export interface AwesomeCategory {
|
|
41
|
+
name: string;
|
|
42
|
+
description?: string;
|
|
43
|
+
descriptionHtml?: string;
|
|
44
|
+
messageRegex?: string;
|
|
45
|
+
traceRegex?: string;
|
|
46
|
+
matchedStatuses?: TestStatus[];
|
|
47
|
+
flaky?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type AwesomeTestResult = Omit<
|
|
51
|
+
TestResult,
|
|
52
|
+
| "runSelector"
|
|
53
|
+
| "sourceMetadata"
|
|
54
|
+
| "expectedResult"
|
|
55
|
+
| "expectedResultHtml"
|
|
56
|
+
| "precondition"
|
|
57
|
+
| "preconditionHtml"
|
|
58
|
+
| "steps"
|
|
59
|
+
| "environment"
|
|
60
|
+
> & {
|
|
61
|
+
setup: AwesomeFixtureResult[];
|
|
62
|
+
teardown: AwesomeFixtureResult[];
|
|
63
|
+
steps: AwesomeTestStepResult[];
|
|
64
|
+
history: HistoryTestResult[];
|
|
65
|
+
retries?: TestResult[];
|
|
66
|
+
groupedLabels: Record<string, string[]>;
|
|
67
|
+
attachments?: AttachmentTestStepResult[];
|
|
68
|
+
breadcrumbs: AwesomeBreadcrumbItem[];
|
|
69
|
+
order?: number;
|
|
70
|
+
groupOrder?: number;
|
|
71
|
+
retry: boolean;
|
|
72
|
+
categories?: AwesomeCategory[];
|
|
73
|
+
environment?: string | "default";
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type AwesomeTreeLeaf = Pick<
|
|
77
|
+
AwesomeTestResult,
|
|
78
|
+
"duration" | "name" | "start" | "status" | "groupOrder" | "flaky" | "retry"
|
|
79
|
+
> & {
|
|
80
|
+
nodeId: string;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type AwesomeTreeGroup = WithChildren & DefaultTreeGroup & { nodeId: string };
|
|
84
|
+
|
|
85
|
+
export type AwesomeTree = TreeData<AwesomeTreeLeaf, AwesomeTreeGroup>;
|
|
86
|
+
/**
|
|
87
|
+
* Tree which contains tree leaves instead of their IDs and recursive trees structure instead of groups
|
|
88
|
+
*/
|
|
89
|
+
export type AwesomeRecursiveTree = DefaultTreeGroup & {
|
|
90
|
+
nodeId: string;
|
|
91
|
+
leaves: AwesomeTreeLeaf[];
|
|
92
|
+
trees: AwesomeRecursiveTree[];
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// TODO: maybe it should call `TestCase` instead of Group
|
|
96
|
+
// TODO: add worst status
|
|
97
|
+
export type AwesomeTestResultGroup = Pick<AwesomeTestResult, "name" | "fullName" | "groupOrder"> & {
|
|
98
|
+
testResults: AwesomeTestResult[];
|
|
99
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import HtmlWebpackPlugin from "html-webpack-plugin";
|
|
2
|
+
import MiniCssExtractPlugin from "mini-css-extract-plugin";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { env } from "node:process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import SpriteLoaderPlugin from "svg-sprite-loader/plugin.js";
|
|
7
|
+
import webpack from "webpack";
|
|
8
|
+
import { WebpackManifestPlugin } from "webpack-manifest-plugin";
|
|
9
|
+
import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin";
|
|
10
|
+
|
|
11
|
+
const baseDir = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
|
|
13
|
+
export default (env, argv) => {
|
|
14
|
+
const devMode = argv?.mode === "development";
|
|
15
|
+
const config = {
|
|
16
|
+
entry: "./src/index.tsx",
|
|
17
|
+
output: {
|
|
18
|
+
path: join(baseDir, "dist"),
|
|
19
|
+
filename: devMode ? "app.js" : "app-[hash:8].js",
|
|
20
|
+
assetModuleFilename: devMode ? `[name].[ext]` : `[name]-[hash:8].[ext]`,
|
|
21
|
+
},
|
|
22
|
+
devtool: devMode ? "inline-source-map" : false,
|
|
23
|
+
module: {
|
|
24
|
+
rules: [
|
|
25
|
+
{
|
|
26
|
+
test: /\.tsx?$/,
|
|
27
|
+
use: "babel-loader",
|
|
28
|
+
exclude: /node_modules/,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
test: /\.css$/,
|
|
32
|
+
use: ["style-loader", "css-loader"],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
test: /\.scss$/,
|
|
36
|
+
use: [
|
|
37
|
+
"style-loader",
|
|
38
|
+
{
|
|
39
|
+
loader: "css-loader",
|
|
40
|
+
options: {
|
|
41
|
+
modules: {
|
|
42
|
+
localIdentName: devMode ? "[path][name]__[local]" : "[hash:base64:8]",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
"sass-loader",
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
test: /\.svg$/,
|
|
51
|
+
loader: "svg-sprite-loader",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
test: /\.(png|jpe?g|gif|woff2?|otf|ttf)$/i,
|
|
55
|
+
type: "asset/inline",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
devServer: {
|
|
60
|
+
hot: true,
|
|
61
|
+
static: "./out/dev",
|
|
62
|
+
historyApiFallback: true,
|
|
63
|
+
watchFiles: ["./src"],
|
|
64
|
+
devMiddleware: {
|
|
65
|
+
index: true,
|
|
66
|
+
mimeTypes: { phtml: "text/html" },
|
|
67
|
+
serverSideRender: false,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
plugins: [
|
|
71
|
+
new ForkTsCheckerPlugin(),
|
|
72
|
+
new webpack.DefinePlugin({
|
|
73
|
+
DEVELOPMENT: devMode,
|
|
74
|
+
}),
|
|
75
|
+
new MiniCssExtractPlugin({
|
|
76
|
+
filename: devMode ? "styles.css" : "styles-[hash:8].css",
|
|
77
|
+
}),
|
|
78
|
+
new SpriteLoaderPlugin(),
|
|
79
|
+
new WebpackManifestPlugin({
|
|
80
|
+
publicPath: "",
|
|
81
|
+
}),
|
|
82
|
+
],
|
|
83
|
+
resolve: {
|
|
84
|
+
modules: ["node_modules"],
|
|
85
|
+
extensions: [".js", ".ts", ".tsx"],
|
|
86
|
+
alias: {
|
|
87
|
+
"@": join(baseDir, "src"),
|
|
88
|
+
"react": "@preact/compat",
|
|
89
|
+
"react-dom": "@preact/compat",
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
config.plugins.push(
|
|
95
|
+
new webpack.optimize.LimitChunkCountPlugin({
|
|
96
|
+
maxChunks: 1,
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (devMode) {
|
|
101
|
+
config.plugins.push(
|
|
102
|
+
new HtmlWebpackPlugin({
|
|
103
|
+
template: "src/index.html",
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return config;
|
|
109
|
+
};
|