@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.
Files changed (58) hide show
  1. package/.babelrc.js +22 -0
  2. package/.eslintrc.cjs +18 -0
  3. package/README.md +0 -0
  4. package/dist/app-af9981fc.js +2 -0
  5. package/dist/app-af9981fc.js.LICENSE.txt +8 -0
  6. package/dist/manifest.json +3 -0
  7. package/package.json +88 -0
  8. package/postcss.config.js +5 -0
  9. package/src/assets/scss/_common.scss +143 -0
  10. package/src/assets/scss/day.scss +51 -0
  11. package/src/assets/scss/fonts.scss +3 -0
  12. package/src/assets/scss/index.scss +7 -0
  13. package/src/assets/scss/night.scss +61 -0
  14. package/src/assets/scss/palette.scss +393 -0
  15. package/src/assets/scss/theme.scss +119 -0
  16. package/src/assets/scss/vars.scss +8 -0
  17. package/src/components/EmptyPlaceholder/index.tsx +24 -0
  18. package/src/components/EmptyPlaceholder/styles.scss +25 -0
  19. package/src/components/Footer/index.tsx +21 -0
  20. package/src/components/Footer/styles.scss +23 -0
  21. package/src/components/Header/index.tsx +15 -0
  22. package/src/components/Header/styles.scss +8 -0
  23. package/src/components/LanguagePicker/index.tsx +40 -0
  24. package/src/components/MetadataRow/index.tsx +20 -0
  25. package/src/components/MetadataRow/styles.scss +9 -0
  26. package/src/components/ReportCard/index.tsx +70 -0
  27. package/src/components/ReportCard/styles.scss +49 -0
  28. package/src/components/ThemeButton/index.tsx +20 -0
  29. package/src/i18n/constants.ts +124 -0
  30. package/src/i18n/locales/az.json +14 -0
  31. package/src/i18n/locales/de.json +14 -0
  32. package/src/i18n/locales/en.json +14 -0
  33. package/src/i18n/locales/es.json +14 -0
  34. package/src/i18n/locales/fr.json +14 -0
  35. package/src/i18n/locales/he.json +14 -0
  36. package/src/i18n/locales/hy.json +13 -0
  37. package/src/i18n/locales/it.json +14 -0
  38. package/src/i18n/locales/ja.json +14 -0
  39. package/src/i18n/locales/ka.json +14 -0
  40. package/src/i18n/locales/kr.json +14 -0
  41. package/src/i18n/locales/nl.json +14 -0
  42. package/src/i18n/locales/pl.json +14 -0
  43. package/src/i18n/locales/pt.json +14 -0
  44. package/src/i18n/locales/ru.json +14 -0
  45. package/src/i18n/locales/sv.json +14 -0
  46. package/src/i18n/locales/tr.json +14 -0
  47. package/src/i18n/locales/zh.json +14 -0
  48. package/src/index.html +89 -0
  49. package/src/index.tsx +59 -0
  50. package/src/stores/index.ts +2 -0
  51. package/src/stores/locale.ts +54 -0
  52. package/src/stores/theme.ts +29 -0
  53. package/src/styles.scss +50 -0
  54. package/src/types/globals.d.ts +13 -0
  55. package/src/types/window.d.ts +10 -0
  56. package/tsconfig.json +27 -0
  57. package/types.d.ts +99 -0
  58. 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,2 @@
1
+ export * from "./theme";
2
+ export * from "./locale";
@@ -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
+ };
@@ -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
+ }
@@ -0,0 +1,13 @@
1
+ declare module "*.svg" {
2
+ const content: {
3
+ id: string;
4
+ };
5
+
6
+ export default content;
7
+ }
8
+
9
+ declare module "*.scss" {
10
+ const content: Record<string, string>;
11
+
12
+ export = content;
13
+ }
@@ -0,0 +1,10 @@
1
+ declare global {
2
+ interface Window {
3
+ reportDataReady: boolean;
4
+ reportData: Record<string, any>;
5
+ // TODO: add the summary type here
6
+ reportSummaries: any;
7
+ }
8
+ }
9
+
10
+ export {};
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
+ };