@allurereport/plugin-awesome 3.0.0-beta.3
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/README.md +57 -0
- package/dist/charts.d.ts +14 -0
- package/dist/charts.js +28 -0
- package/dist/converters.d.ts +5 -0
- package/dist/converters.js +48 -0
- package/dist/generators.d.ts +19 -0
- package/dist/generators.js +189 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/model.d.ts +14 -0
- package/dist/model.js +1 -0
- package/dist/plugin.d.ts +10 -0
- package/dist/plugin.js +71 -0
- package/dist/writer.d.ts +36 -0
- package/dist/writer.js +82 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Awesome Plugin
|
|
2
|
+
|
|
3
|
+
[<img src="https://allurereport.org/public/img/allure-report.svg" height="85px" alt="Allure Report logo" align="right" />](https://allurereport.org "Allure Report")
|
|
4
|
+
|
|
5
|
+
- Learn more about Allure Report at https://allurereport.org
|
|
6
|
+
- 📚 [Documentation](https://allurereport.org/docs/) – discover official documentation for Allure Report
|
|
7
|
+
- ❓ [Questions and Support](https://github.com/orgs/allure-framework/discussions/categories/questions-support) – get help from the team and community
|
|
8
|
+
- 📢 [Official announcements](https://github.com/orgs/allure-framework/discussions/categories/announcements) – be in touch with the latest updates
|
|
9
|
+
- 💬 [General Discussion ](https://github.com/orgs/allure-framework/discussions/categories/general-discussion) – engage in casual conversations, share insights and ideas with the community
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
The plugin generates brand new Allure Report with modern design and new features.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
Use your favorite package manager to install the package:
|
|
20
|
+
|
|
21
|
+
```shell
|
|
22
|
+
npm add @allurereport/plugin-awesome
|
|
23
|
+
yarn add @allurereport/plugin-awesome
|
|
24
|
+
pnpm add @allurereport/plugin-awesome
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then, add the plugin to the Allure configuration file:
|
|
28
|
+
|
|
29
|
+
```diff
|
|
30
|
+
import { defineConfig } from "allure";
|
|
31
|
+
|
|
32
|
+
export default defineConfig({
|
|
33
|
+
name: "Allure Report",
|
|
34
|
+
output: "./allure-report",
|
|
35
|
+
historyPath: "./history.jsonl",
|
|
36
|
+
plugins: {
|
|
37
|
+
+ awesome: {
|
|
38
|
+
+ options: {
|
|
39
|
+
+ reportName: "HelloWorld",
|
|
40
|
+
+ },
|
|
41
|
+
+ },
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Options
|
|
47
|
+
|
|
48
|
+
The plugin accepts the following options:
|
|
49
|
+
|
|
50
|
+
| Option | Description | Type | Default |
|
|
51
|
+
|------------------|-------------------------------------------------|--------------------------------------------------------------|-----------------|
|
|
52
|
+
| `reportName` | Name of the report | `string` | `Allure Report` |
|
|
53
|
+
| `singleFile` | Writes the report as a single `index.html` file | `boolean` | `false` |
|
|
54
|
+
| `logo` | Path to the logo image | `string` | `null` |
|
|
55
|
+
| `theme` | Default color theme of the report | `light \| dark` | OS theme |
|
|
56
|
+
| `reportLanguage` | Default language of the report | `string` | OS language |
|
|
57
|
+
| `ci` | CI data which will be rendered in the report | `{ type: "github" \| "jenkins", url: string, name: string }` | `undefined` |
|
package/dist/charts.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Statistic, TestStatus } from "@allurereport/core-api";
|
|
2
|
+
import { PieArcDatum } from "d3-shape";
|
|
3
|
+
export type TestResultSlice = {
|
|
4
|
+
status: TestStatus;
|
|
5
|
+
count: number;
|
|
6
|
+
};
|
|
7
|
+
export type TestResultChartData = {
|
|
8
|
+
percentage: number;
|
|
9
|
+
slices: TestResultSlice[];
|
|
10
|
+
};
|
|
11
|
+
export declare const d3Arc: import("d3-shape").Arc<any, PieArcDatum<TestResultSlice>>;
|
|
12
|
+
export declare const d3Pie: import("d3-shape").Pie<any, TestResultSlice>;
|
|
13
|
+
export declare function getPercentage(value: number, total: number): number;
|
|
14
|
+
export declare const getChartData: (stats: Statistic) => TestResultChartData;
|
package/dist/charts.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { statusesList } from "@allurereport/core-api";
|
|
2
|
+
import { arc, pie } from "d3-shape";
|
|
3
|
+
export const d3Arc = arc().innerRadius(40).outerRadius(50).cornerRadius(2).padAngle(0.03);
|
|
4
|
+
export const d3Pie = pie()
|
|
5
|
+
.value((d) => d.count)
|
|
6
|
+
.padAngle(0.03)
|
|
7
|
+
.sortValues((a, b) => a - b);
|
|
8
|
+
export function getPercentage(value, total) {
|
|
9
|
+
return Math.floor((value / total) * 10000) / 100;
|
|
10
|
+
}
|
|
11
|
+
export const getChartData = (stats) => {
|
|
12
|
+
const convertedStatuses = statusesList
|
|
13
|
+
.filter((status) => !!stats?.[status])
|
|
14
|
+
.map((status) => ({
|
|
15
|
+
status,
|
|
16
|
+
count: stats[status],
|
|
17
|
+
}));
|
|
18
|
+
const arcsData = d3Pie(convertedStatuses);
|
|
19
|
+
const slices = arcsData.map((arc) => ({
|
|
20
|
+
d: d3Arc(arc),
|
|
21
|
+
...arc.data,
|
|
22
|
+
}));
|
|
23
|
+
const percentage = getPercentage(stats.passed ?? 0, stats.total);
|
|
24
|
+
return {
|
|
25
|
+
slices,
|
|
26
|
+
percentage,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TestFixtureResult, TestResult, TestStepResult } from "@allurereport/core-api";
|
|
2
|
+
import type { AllureAwesomeFixtureResult, AllureAwesomeTestResult, AllureAwesomeTestStepResult } from "@allurereport/web-awesome";
|
|
3
|
+
export declare const convertTestResult: (tr: TestResult) => AllureAwesomeTestResult;
|
|
4
|
+
export declare const convertTestStepResult: (tsr: TestStepResult) => AllureAwesomeTestStepResult;
|
|
5
|
+
export declare const convertFixtureResult: (fr: TestFixtureResult) => AllureAwesomeFixtureResult;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const mapLabelsByName = (labels) => {
|
|
2
|
+
return labels.reduce((acc, { name, value }) => {
|
|
3
|
+
acc[name] = acc[name] || [];
|
|
4
|
+
if (value) {
|
|
5
|
+
acc[name].push(value);
|
|
6
|
+
}
|
|
7
|
+
return acc;
|
|
8
|
+
}, {});
|
|
9
|
+
};
|
|
10
|
+
export const convertTestResult = (tr) => {
|
|
11
|
+
return {
|
|
12
|
+
id: tr.id,
|
|
13
|
+
name: tr.name,
|
|
14
|
+
duration: tr.duration,
|
|
15
|
+
status: tr.status,
|
|
16
|
+
fullName: tr.fullName,
|
|
17
|
+
historyId: tr.historyId,
|
|
18
|
+
flaky: tr.flaky,
|
|
19
|
+
muted: tr.muted,
|
|
20
|
+
known: tr.known,
|
|
21
|
+
hidden: tr.hidden,
|
|
22
|
+
labels: tr.labels,
|
|
23
|
+
groupedLabels: mapLabelsByName(tr.labels),
|
|
24
|
+
parameters: tr.parameters,
|
|
25
|
+
links: tr.links,
|
|
26
|
+
steps: tr.steps,
|
|
27
|
+
message: tr.message,
|
|
28
|
+
trace: tr.trace,
|
|
29
|
+
setup: [],
|
|
30
|
+
teardown: [],
|
|
31
|
+
history: [],
|
|
32
|
+
retries: [],
|
|
33
|
+
breadcrumbs: [],
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export const convertTestStepResult = (tsr) => {
|
|
37
|
+
return tsr;
|
|
38
|
+
};
|
|
39
|
+
export const convertFixtureResult = (fr) => {
|
|
40
|
+
return {
|
|
41
|
+
id: fr.id,
|
|
42
|
+
type: fr.type,
|
|
43
|
+
name: fr.name,
|
|
44
|
+
status: fr.status,
|
|
45
|
+
steps: fr.steps.map(convertTestStepResult),
|
|
46
|
+
duration: fr.duration,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AttachmentLink, EnvironmentItem, Statistic, TestResult } from "@allurereport/core-api";
|
|
2
|
+
import type { AllureStore, ReportFiles, ResultFile } from "@allurereport/plugin-api";
|
|
3
|
+
import type { AllureAwesomeOptions, TemplateManifest } from "./model.js";
|
|
4
|
+
import type { AllureAwesomeDataWriter, ReportFile } from "./writer.js";
|
|
5
|
+
export declare const readTemplateManifest: (singleFileMode?: boolean) => Promise<TemplateManifest>;
|
|
6
|
+
export declare const generateTestResults: (writer: AllureAwesomeDataWriter, store: AllureStore) => Promise<void>;
|
|
7
|
+
export declare const generateTree: (writer: AllureAwesomeDataWriter, treeName: string, labels: string[], tests: TestResult[]) => Promise<void>;
|
|
8
|
+
export declare const generateEnvironmentJson: (writer: AllureAwesomeDataWriter, env: EnvironmentItem[]) => Promise<void>;
|
|
9
|
+
export declare const generateStatistic: (writer: AllureAwesomeDataWriter, statistic: Statistic) => Promise<void>;
|
|
10
|
+
export declare const generatePieChart: (writer: AllureAwesomeDataWriter, statistic: Statistic) => Promise<void>;
|
|
11
|
+
export declare const generateAttachmentsFiles: (writer: AllureAwesomeDataWriter, attachmentLinks: AttachmentLink[], contentFunction: (id: string) => Promise<ResultFile | undefined>) => Promise<Map<string, string> | undefined>;
|
|
12
|
+
export declare const generateHistoryDataPoints: (writer: AllureAwesomeDataWriter, store: AllureStore) => Promise<Map<string, string>>;
|
|
13
|
+
export declare const generateStaticFiles: (payload: AllureAwesomeOptions & {
|
|
14
|
+
allureVersion: string;
|
|
15
|
+
reportFiles: ReportFiles;
|
|
16
|
+
reportDataFiles: ReportFile[];
|
|
17
|
+
reportUuid: string;
|
|
18
|
+
reportName: string;
|
|
19
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { createTreeByLabels } from "@allurereport/plugin-api";
|
|
2
|
+
import { createBaseUrlScript, createFontLinkTag, createReportDataScript, createScriptTag, createStylesLinkTag, } from "@allurereport/web-commons";
|
|
3
|
+
import Handlebars from "handlebars";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { basename, join } from "node:path";
|
|
7
|
+
import { getChartData } from "./charts.js";
|
|
8
|
+
import { convertFixtureResult, convertTestResult } from "./converters.js";
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const template = `<!DOCTYPE html>
|
|
11
|
+
<html dir="ltr" lang="en">
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="utf-8">
|
|
14
|
+
<title> {{ reportName }} </title>
|
|
15
|
+
<link rel="icon" href="favicon.ico">
|
|
16
|
+
{{{ headTags }}}
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<div id="app"></div>
|
|
20
|
+
${createBaseUrlScript()}
|
|
21
|
+
<script>
|
|
22
|
+
window.allure = window.allure || {};
|
|
23
|
+
</script>
|
|
24
|
+
{{{ bodyTags }}}
|
|
25
|
+
{{#if analyticsEnable}}
|
|
26
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-LNDJ3J7WT0"></script>
|
|
27
|
+
<script>
|
|
28
|
+
window.dataLayer = window.dataLayer || [];
|
|
29
|
+
function gtag(){dataLayer.push(arguments);}
|
|
30
|
+
gtag('js', new Date());
|
|
31
|
+
gtag('config', 'G-LNDJ3J7WT0', {
|
|
32
|
+
"report": "awesome",
|
|
33
|
+
"allureVersion": "{{ allureVersion }}",
|
|
34
|
+
"reportUuid": "{{ reportUuid }}",
|
|
35
|
+
"single_file": "{{singleFile}}"
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
{{/if}}
|
|
39
|
+
<script>
|
|
40
|
+
window.allureReportOptions = {{{ reportOptions }}}
|
|
41
|
+
</script>
|
|
42
|
+
{{{ reportFilesScript }}}
|
|
43
|
+
</body>
|
|
44
|
+
</html>
|
|
45
|
+
`;
|
|
46
|
+
export const readTemplateManifest = async (singleFileMode) => {
|
|
47
|
+
const templateManifestSource = require.resolve(`@allurereport/web-awesome/dist/${singleFileMode ? "single" : "multi"}/manifest.json`);
|
|
48
|
+
const templateManifest = await readFile(templateManifestSource, { encoding: "utf-8" });
|
|
49
|
+
return JSON.parse(templateManifest);
|
|
50
|
+
};
|
|
51
|
+
const createBreadcrumbs = (convertedTr) => {
|
|
52
|
+
const labelsByType = convertedTr.labels.reduce((acc, label) => {
|
|
53
|
+
if (!acc[label.name]) {
|
|
54
|
+
acc[label.name] = [];
|
|
55
|
+
}
|
|
56
|
+
acc[label.name].push(label.value || "");
|
|
57
|
+
return acc;
|
|
58
|
+
}, {});
|
|
59
|
+
const parentSuites = labelsByType.parentSuite || [""];
|
|
60
|
+
const suites = labelsByType.suite || [""];
|
|
61
|
+
const subSuites = labelsByType.subSuite || [""];
|
|
62
|
+
return parentSuites.reduce((acc, parentSuite) => {
|
|
63
|
+
suites.forEach((suite) => {
|
|
64
|
+
subSuites.forEach((subSuite) => {
|
|
65
|
+
const path = [parentSuite, suite, subSuite].filter(Boolean);
|
|
66
|
+
if (path.length > 0) {
|
|
67
|
+
acc.push(path);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
return acc;
|
|
72
|
+
}, []);
|
|
73
|
+
};
|
|
74
|
+
export const generateTestResults = async (writer, store) => {
|
|
75
|
+
const allTr = await store.allTestResults({ includeHidden: true });
|
|
76
|
+
const convertedTrs = [];
|
|
77
|
+
for (const tr of allTr) {
|
|
78
|
+
const trFixtures = await store.fixturesByTrId(tr.id);
|
|
79
|
+
const convertedTrFixtures = trFixtures.map(convertFixtureResult);
|
|
80
|
+
const convertedTr = convertTestResult(tr);
|
|
81
|
+
convertedTr.history = await store.historyByTrId(tr.id);
|
|
82
|
+
convertedTr.retries = await store.retriesByTrId(tr.id);
|
|
83
|
+
convertedTr.setup = convertedTrFixtures.filter((f) => f.type === "before");
|
|
84
|
+
convertedTr.teardown = convertedTrFixtures.filter((f) => f.type === "after");
|
|
85
|
+
convertedTr.attachments = (await store.attachmentsByTrId(tr.id)).map((attachment) => ({
|
|
86
|
+
link: attachment,
|
|
87
|
+
type: "attachment",
|
|
88
|
+
}));
|
|
89
|
+
convertedTr.breadcrumbs = createBreadcrumbs(convertedTr);
|
|
90
|
+
convertedTrs.push(convertedTr);
|
|
91
|
+
}
|
|
92
|
+
for (const convertedTr of convertedTrs) {
|
|
93
|
+
await writer.writeTestCase(convertedTr);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
export const generateTree = async (writer, treeName, labels, tests) => {
|
|
97
|
+
const visibleTests = tests.filter((test) => !test.hidden);
|
|
98
|
+
const tree = createTreeByLabels(visibleTests, labels);
|
|
99
|
+
await writer.writeWidget(`${treeName}.json`, tree);
|
|
100
|
+
};
|
|
101
|
+
export const generateEnvironmentJson = async (writer, env) => {
|
|
102
|
+
await writer.writeWidget("allure_environment.json", env);
|
|
103
|
+
};
|
|
104
|
+
export const generateStatistic = async (writer, statistic) => {
|
|
105
|
+
await writer.writeWidget("allure_statistic.json", statistic);
|
|
106
|
+
};
|
|
107
|
+
export const generatePieChart = async (writer, statistic) => {
|
|
108
|
+
const chartData = getChartData(statistic);
|
|
109
|
+
await writer.writeWidget("allure_pie_chart.json", chartData);
|
|
110
|
+
};
|
|
111
|
+
export const generateAttachmentsFiles = async (writer, attachmentLinks, contentFunction) => {
|
|
112
|
+
const result = new Map();
|
|
113
|
+
for (const { id, ext, ...link } of attachmentLinks) {
|
|
114
|
+
if (link.missed) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const content = await contentFunction(id);
|
|
118
|
+
if (!content) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const src = `${id}${ext}`;
|
|
122
|
+
await writer.writeAttachment(src, content);
|
|
123
|
+
result.set(id, src);
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
126
|
+
};
|
|
127
|
+
export const generateHistoryDataPoints = async (writer, store) => {
|
|
128
|
+
const result = new Map();
|
|
129
|
+
const allHistoryPoints = await store.allHistoryDataPoints();
|
|
130
|
+
allHistoryPoints.sort((a, b) => b.timestamp - a.timestamp);
|
|
131
|
+
for (const historyPoint of allHistoryPoints?.slice(0, 6)) {
|
|
132
|
+
const src = `history/${historyPoint.uuid}.json`;
|
|
133
|
+
await writer.writeData(src, historyPoint);
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
};
|
|
137
|
+
export const generateStaticFiles = async (payload) => {
|
|
138
|
+
const { reportName = "Allure Report", reportLanguage = "en", singleFile, logo = "", theme = "light", reportFiles, reportDataFiles, reportUuid, allureVersion, } = payload;
|
|
139
|
+
const compile = Handlebars.compile(template);
|
|
140
|
+
const manifest = await readTemplateManifest(payload.singleFile);
|
|
141
|
+
const headTags = [];
|
|
142
|
+
const bodyTags = [];
|
|
143
|
+
if (!payload.singleFile) {
|
|
144
|
+
for (const key in manifest) {
|
|
145
|
+
const fileName = manifest[key];
|
|
146
|
+
const filePath = require.resolve(join("@allurereport/web-awesome/dist", singleFile ? "single" : "multi", fileName));
|
|
147
|
+
if (key.includes(".woff")) {
|
|
148
|
+
headTags.push(createFontLinkTag(fileName));
|
|
149
|
+
}
|
|
150
|
+
if (key === "main.css") {
|
|
151
|
+
headTags.push(createStylesLinkTag(fileName));
|
|
152
|
+
}
|
|
153
|
+
if (key === "main.js") {
|
|
154
|
+
bodyTags.push(createScriptTag(fileName));
|
|
155
|
+
}
|
|
156
|
+
if (singleFile) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const fileContent = await readFile(filePath);
|
|
160
|
+
await reportFiles.addFile(basename(filePath), fileContent);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const mainJs = manifest["main.js"];
|
|
165
|
+
const mainJsSource = require.resolve(`@allurereport/web-awesome/dist/single/${mainJs}`);
|
|
166
|
+
const mainJsContentBuffer = await readFile(mainJsSource);
|
|
167
|
+
bodyTags.push(createScriptTag(`data:text/javascript;base64,${mainJsContentBuffer.toString("base64")}`));
|
|
168
|
+
}
|
|
169
|
+
const reportOptions = {
|
|
170
|
+
reportName,
|
|
171
|
+
logo,
|
|
172
|
+
theme,
|
|
173
|
+
reportLanguage,
|
|
174
|
+
createdAt: Date.now(),
|
|
175
|
+
reportUuid,
|
|
176
|
+
};
|
|
177
|
+
const html = compile({
|
|
178
|
+
headTags: headTags.join("\n"),
|
|
179
|
+
bodyTags: bodyTags.join("\n"),
|
|
180
|
+
reportFilesScript: createReportDataScript(reportDataFiles),
|
|
181
|
+
reportOptions: JSON.stringify(reportOptions),
|
|
182
|
+
analyticsEnable: true,
|
|
183
|
+
allureVersion,
|
|
184
|
+
reportUuid,
|
|
185
|
+
reportName,
|
|
186
|
+
singleFile: payload.singleFile,
|
|
187
|
+
});
|
|
188
|
+
await reportFiles.addFile("index.html", Buffer.from(html, "utf8"));
|
|
189
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/model.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type AllureAwesomeOptions = {
|
|
2
|
+
reportName?: string;
|
|
3
|
+
singleFile?: boolean;
|
|
4
|
+
logo?: string;
|
|
5
|
+
theme?: "light" | "dark";
|
|
6
|
+
reportLanguage?: "en" | "ru";
|
|
7
|
+
ci?: {
|
|
8
|
+
type: "github" | "jenkins";
|
|
9
|
+
url: string;
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export type TemplateManifest = Record<string, string>;
|
|
14
|
+
export type AllureAwesomePluginOptions = AllureAwesomeOptions;
|
package/dist/model.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AllureStore, Plugin, PluginContext } from "@allurereport/plugin-api";
|
|
2
|
+
import type { AllureAwesomePluginOptions } from "./model.js";
|
|
3
|
+
export declare class AllureAwesomePlugin implements Plugin {
|
|
4
|
+
#private;
|
|
5
|
+
readonly options: AllureAwesomePluginOptions;
|
|
6
|
+
constructor(options?: AllureAwesomePluginOptions);
|
|
7
|
+
start: (context: PluginContext) => Promise<void>;
|
|
8
|
+
update: (context: PluginContext, store: AllureStore) => Promise<void>;
|
|
9
|
+
done: (context: PluginContext, store: AllureStore) => Promise<void>;
|
|
10
|
+
}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
|
+
};
|
|
12
|
+
var _AllureAwesomePlugin_writer, _AllureAwesomePlugin_generate;
|
|
13
|
+
import { findByLabelName } from "@allurereport/core-api";
|
|
14
|
+
import { generateAttachmentsFiles, generateEnvironmentJson, generateHistoryDataPoints, generatePieChart, generateStaticFiles, generateStatistic, generateTestResults, generateTree, } from "./generators.js";
|
|
15
|
+
import { InMemoryReportDataWriter, ReportFileDataWriter } from "./writer.js";
|
|
16
|
+
export class AllureAwesomePlugin {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.options = options;
|
|
19
|
+
_AllureAwesomePlugin_writer.set(this, void 0);
|
|
20
|
+
_AllureAwesomePlugin_generate.set(this, async (context, store) => {
|
|
21
|
+
const { singleFile } = this.options ?? {};
|
|
22
|
+
const environmentItems = await store.metadataByKey("allure_environment");
|
|
23
|
+
const statistic = await store.testsStatistic();
|
|
24
|
+
const allTr = await store.allTestResults({ includeHidden: true });
|
|
25
|
+
const attachments = await store.allAttachments();
|
|
26
|
+
await generateStatistic(__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f"), statistic);
|
|
27
|
+
await generatePieChart(__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f"), statistic);
|
|
28
|
+
const noParentSuite = allTr.find((tr) => findByLabelName(tr.labels, "parentSuite")) === undefined;
|
|
29
|
+
await generateTree(__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f"), "suites", noParentSuite ? ["suite", "subSuite"] : ["parentSuite", "suite", "subSuite"], allTr);
|
|
30
|
+
await generateTestResults(__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f"), store);
|
|
31
|
+
await generateHistoryDataPoints(__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f"), store);
|
|
32
|
+
if (environmentItems?.length) {
|
|
33
|
+
await generateEnvironmentJson(__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f"), environmentItems);
|
|
34
|
+
}
|
|
35
|
+
if (attachments?.length) {
|
|
36
|
+
await generateAttachmentsFiles(__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f"), attachments, (id) => store.attachmentContentById(id));
|
|
37
|
+
}
|
|
38
|
+
const reportDataFiles = singleFile ? __classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f").reportFiles() : [];
|
|
39
|
+
await generateStaticFiles({
|
|
40
|
+
...this.options,
|
|
41
|
+
allureVersion: context.allureVersion,
|
|
42
|
+
reportFiles: context.reportFiles,
|
|
43
|
+
reportDataFiles,
|
|
44
|
+
reportUuid: context.reportUuid,
|
|
45
|
+
reportName: context.reportName,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
this.start = async (context) => {
|
|
49
|
+
const { singleFile } = this.options;
|
|
50
|
+
if (singleFile) {
|
|
51
|
+
__classPrivateFieldSet(this, _AllureAwesomePlugin_writer, new InMemoryReportDataWriter(), "f");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
__classPrivateFieldSet(this, _AllureAwesomePlugin_writer, new ReportFileDataWriter(context.reportFiles), "f");
|
|
55
|
+
await Promise.resolve();
|
|
56
|
+
};
|
|
57
|
+
this.update = async (context, store) => {
|
|
58
|
+
if (!__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f")) {
|
|
59
|
+
throw new Error("call start first");
|
|
60
|
+
}
|
|
61
|
+
await __classPrivateFieldGet(this, _AllureAwesomePlugin_generate, "f").call(this, context, store);
|
|
62
|
+
};
|
|
63
|
+
this.done = async (context, store) => {
|
|
64
|
+
if (!__classPrivateFieldGet(this, _AllureAwesomePlugin_writer, "f")) {
|
|
65
|
+
throw new Error("call start first");
|
|
66
|
+
}
|
|
67
|
+
await __classPrivateFieldGet(this, _AllureAwesomePlugin_generate, "f").call(this, context, store);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
_AllureAwesomePlugin_writer = new WeakMap(), _AllureAwesomePlugin_generate = new WeakMap();
|
package/dist/writer.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ReportFiles, ResultFile } from "@allurereport/plugin-api";
|
|
2
|
+
import type { AllureAwesomeTestResult } from "@allurereport/web-awesome";
|
|
3
|
+
export interface ReportFile {
|
|
4
|
+
name: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AllureAwesomeDataWriter {
|
|
8
|
+
writeData(fileName: string, data: any): Promise<void>;
|
|
9
|
+
writeWidget(fileName: string, data: any): Promise<void>;
|
|
10
|
+
writeTestCase(test: AllureAwesomeTestResult): Promise<void>;
|
|
11
|
+
writeAttachment(source: string, file: ResultFile): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare class FileSystemReportDataWriter implements AllureAwesomeDataWriter {
|
|
14
|
+
private readonly output;
|
|
15
|
+
constructor(output: string);
|
|
16
|
+
writeData(fileName: string, data: any): Promise<void>;
|
|
17
|
+
writeWidget(fileName: string, data: any): Promise<void>;
|
|
18
|
+
writeTestCase(test: AllureAwesomeTestResult): Promise<void>;
|
|
19
|
+
writeAttachment(source: string, file: ResultFile): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export declare class InMemoryReportDataWriter implements AllureAwesomeDataWriter {
|
|
22
|
+
#private;
|
|
23
|
+
writeData(fileName: string, data: any): Promise<void>;
|
|
24
|
+
writeWidget(fileName: string, data: any): Promise<void>;
|
|
25
|
+
writeTestCase(test: AllureAwesomeTestResult): Promise<void>;
|
|
26
|
+
writeAttachment(fileName: string, file: ResultFile): Promise<void>;
|
|
27
|
+
reportFiles(): ReportFile[];
|
|
28
|
+
}
|
|
29
|
+
export declare class ReportFileDataWriter implements AllureAwesomeDataWriter {
|
|
30
|
+
readonly reportFiles: ReportFiles;
|
|
31
|
+
constructor(reportFiles: ReportFiles);
|
|
32
|
+
writeData(fileName: string, data: any): Promise<void>;
|
|
33
|
+
writeWidget(fileName: string, data: any): Promise<void>;
|
|
34
|
+
writeAttachment(source: string, file: ResultFile): Promise<void>;
|
|
35
|
+
writeTestCase(test: AllureAwesomeTestResult): Promise<void>;
|
|
36
|
+
}
|
package/dist/writer.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var _InMemoryReportDataWriter_data;
|
|
7
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
8
|
+
import { join, resolve } from "node:path";
|
|
9
|
+
export class FileSystemReportDataWriter {
|
|
10
|
+
constructor(output) {
|
|
11
|
+
this.output = output;
|
|
12
|
+
}
|
|
13
|
+
async writeData(fileName, data) {
|
|
14
|
+
const distFolder = resolve(this.output, "data");
|
|
15
|
+
await mkdir(distFolder, { recursive: true });
|
|
16
|
+
await writeFile(resolve(distFolder, fileName), JSON.stringify(data), { encoding: "utf-8" });
|
|
17
|
+
}
|
|
18
|
+
async writeWidget(fileName, data) {
|
|
19
|
+
const distFolder = resolve(this.output, "widgets");
|
|
20
|
+
await mkdir(distFolder, { recursive: true });
|
|
21
|
+
await writeFile(resolve(distFolder, fileName), JSON.stringify(data), { encoding: "utf-8" });
|
|
22
|
+
}
|
|
23
|
+
async writeTestCase(test) {
|
|
24
|
+
const distFolder = resolve(this.output, "data", "test-results");
|
|
25
|
+
await mkdir(distFolder, { recursive: true });
|
|
26
|
+
await writeFile(resolve(distFolder, `${test.id}.json`), JSON.stringify(test), { encoding: "utf-8" });
|
|
27
|
+
}
|
|
28
|
+
async writeAttachment(source, file) {
|
|
29
|
+
const distFolder = resolve(this.output, "data", "attachments");
|
|
30
|
+
await mkdir(distFolder, { recursive: true });
|
|
31
|
+
await file.writeTo(resolve(distFolder, source));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export class InMemoryReportDataWriter {
|
|
35
|
+
constructor() {
|
|
36
|
+
_InMemoryReportDataWriter_data.set(this, {});
|
|
37
|
+
}
|
|
38
|
+
async writeData(fileName, data) {
|
|
39
|
+
const dist = join("data", fileName);
|
|
40
|
+
__classPrivateFieldGet(this, _InMemoryReportDataWriter_data, "f")[dist] = Buffer.from(JSON.stringify(data), "utf-8");
|
|
41
|
+
}
|
|
42
|
+
async writeWidget(fileName, data) {
|
|
43
|
+
const dist = join("widgets", fileName);
|
|
44
|
+
__classPrivateFieldGet(this, _InMemoryReportDataWriter_data, "f")[dist] = Buffer.from(JSON.stringify(data), "utf-8");
|
|
45
|
+
}
|
|
46
|
+
async writeTestCase(test) {
|
|
47
|
+
const dist = join("data", "test-results", `${test.id}.json`);
|
|
48
|
+
__classPrivateFieldGet(this, _InMemoryReportDataWriter_data, "f")[dist] = Buffer.from(JSON.stringify(test), "utf-8");
|
|
49
|
+
}
|
|
50
|
+
async writeAttachment(fileName, file) {
|
|
51
|
+
const dist = join("data", "attachments", fileName);
|
|
52
|
+
const content = await file.asBuffer();
|
|
53
|
+
if (content) {
|
|
54
|
+
__classPrivateFieldGet(this, _InMemoryReportDataWriter_data, "f")[dist] = content;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
reportFiles() {
|
|
58
|
+
return Object.keys(__classPrivateFieldGet(this, _InMemoryReportDataWriter_data, "f")).map((key) => ({ name: key, value: __classPrivateFieldGet(this, _InMemoryReportDataWriter_data, "f")[key].toString("base64") }));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
_InMemoryReportDataWriter_data = new WeakMap();
|
|
62
|
+
export class ReportFileDataWriter {
|
|
63
|
+
constructor(reportFiles) {
|
|
64
|
+
this.reportFiles = reportFiles;
|
|
65
|
+
}
|
|
66
|
+
async writeData(fileName, data) {
|
|
67
|
+
await this.reportFiles.addFile(join("data", fileName), Buffer.from(JSON.stringify(data), "utf-8"));
|
|
68
|
+
}
|
|
69
|
+
async writeWidget(fileName, data) {
|
|
70
|
+
await this.reportFiles.addFile(join("widgets", fileName), Buffer.from(JSON.stringify(data), "utf-8"));
|
|
71
|
+
}
|
|
72
|
+
async writeAttachment(source, file) {
|
|
73
|
+
const contentBuffer = await file.asBuffer();
|
|
74
|
+
if (!contentBuffer) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
await this.reportFiles.addFile(join("data", "attachments", source), contentBuffer);
|
|
78
|
+
}
|
|
79
|
+
async writeTestCase(test) {
|
|
80
|
+
await this.reportFiles.addFile(join("data", "test-results", `${test.id}.json`), Buffer.from(JSON.stringify(test), "utf8"));
|
|
81
|
+
}
|
|
82
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@allurereport/plugin-awesome",
|
|
3
|
+
"version": "3.0.0-beta.3",
|
|
4
|
+
"description": "Allure Awesome Plugin – brand new HTML report with modern design and new features",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"allure",
|
|
7
|
+
"testing",
|
|
8
|
+
"report",
|
|
9
|
+
"plugin",
|
|
10
|
+
"html"
|
|
11
|
+
],
|
|
12
|
+
"repository": "https://github.com/allure-framework/allure3",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"author": "Qameta Software",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"module": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"files": [
|
|
23
|
+
"./dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "run clean && tsc --project ./tsconfig.json",
|
|
27
|
+
"clean": "rimraf ./dist",
|
|
28
|
+
"test": "rimraf ./out && vitest run"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@allurereport/core-api": "3.0.0-beta.3",
|
|
32
|
+
"@allurereport/plugin-api": "3.0.0-beta.3",
|
|
33
|
+
"@allurereport/web-awesome": "3.0.0-beta.3",
|
|
34
|
+
"@allurereport/web-commons": "3.0.0-beta.3",
|
|
35
|
+
"d3-shape": "^3.2.0",
|
|
36
|
+
"handlebars": "^4.7.8"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@stylistic/eslint-plugin": "^2.6.1",
|
|
40
|
+
"@types/d3-shape": "^3.1.6",
|
|
41
|
+
"@types/eslint": "^8.56.11",
|
|
42
|
+
"@types/node": "^20.17.9",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
44
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
45
|
+
"@vitest/runner": "^2.1.8",
|
|
46
|
+
"allure-vitest": "^3.0.7",
|
|
47
|
+
"eslint": "^8.57.0",
|
|
48
|
+
"eslint-config-prettier": "^9.1.0",
|
|
49
|
+
"eslint-plugin-import": "^2.29.1",
|
|
50
|
+
"eslint-plugin-jsdoc": "^50.0.0",
|
|
51
|
+
"eslint-plugin-n": "^17.10.1",
|
|
52
|
+
"eslint-plugin-no-null": "^1.0.2",
|
|
53
|
+
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
54
|
+
"rimraf": "^6.0.1",
|
|
55
|
+
"typescript": "^5.6.3",
|
|
56
|
+
"vitest": "^2.1.8"
|
|
57
|
+
}
|
|
58
|
+
}
|