@allurereport/plugin-awesome 3.0.0-beta.23 → 3.0.0-beta.25

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 CHANGED
@@ -47,12 +47,13 @@ export default defineConfig({
47
47
 
48
48
  The plugin accepts the following options:
49
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` |
58
- | `groupBy` | By default, tests are grouped using the `titlePath` provided by the test framework. | `string`| Grouping by `titlepath` |
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 \| auto` | `auto` 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` |
58
+ | `groupBy` | Grouping tests by labels or combining labels. By default, tests are grouped using the `titlePath` provided by the test framework. | `string` | `[]`(Grouping by `titlepath`) |
59
+ | `appendTitlePath`| Special marker for `groupBy`. Forces a final grouping by `titlePath` after all label-based groups. | `boolean` | `false` |
@@ -0,0 +1,7 @@
1
+ import type { AllureStore } from "@allurereport/plugin-api";
2
+ import type { AwesomeOptions } from "./model.js";
3
+ type Writer = {
4
+ writeWidget(fileName: string, data: any): Promise<void>;
5
+ };
6
+ export declare const generateTimeline: (writer: Writer, store: AllureStore, options: AwesomeOptions) => Promise<void>;
7
+ export {};
@@ -0,0 +1,39 @@
1
+ import { hasLabels } from "@allurereport/web-commons";
2
+ const DEFAULT_MIN_DURATION = 1;
3
+ const HOST_LABEL = "host";
4
+ const THREAD_LABEL = "thread";
5
+ export const generateTimeline = async (writer, store, options) => {
6
+ if (!options.timeline) {
7
+ return;
8
+ }
9
+ const testResults = await store.allTestResults({ includeHidden: true });
10
+ const { minDuration = DEFAULT_MIN_DURATION } = options.timeline;
11
+ const result = [];
12
+ for (const test of testResults) {
13
+ const hasStart = Number.isInteger(test.start);
14
+ const hasStop = Number.isInteger(test.stop);
15
+ if (!hasStart || !hasStop) {
16
+ continue;
17
+ }
18
+ const duration = test.duration ?? test.stop - test.start;
19
+ if (duration < minDuration) {
20
+ continue;
21
+ }
22
+ if (!hasLabels(test, [HOST_LABEL, THREAD_LABEL])) {
23
+ continue;
24
+ }
25
+ result.push({
26
+ id: test.id,
27
+ historyId: test.historyId,
28
+ name: test.name,
29
+ status: test.status,
30
+ hidden: test.hidden,
31
+ labels: test.labels,
32
+ environment: test.environment,
33
+ start: test.start,
34
+ stop: test.stop,
35
+ duration: duration,
36
+ });
37
+ }
38
+ await writer.writeWidget("timeline.json", result);
39
+ };
@@ -8,7 +8,9 @@ export declare const generateTestResults: (writer: AwesomeDataWriter, store: All
8
8
  export declare const generateTestCases: (writer: AwesomeDataWriter, trs: AwesomeTestResult[]) => Promise<void>;
9
9
  export declare const generateTestEnvGroups: (writer: AwesomeDataWriter, groups: TestEnvGroup[]) => Promise<void>;
10
10
  export declare const generateNav: (writer: AwesomeDataWriter, trs: AwesomeTestResult[], filename?: string) => Promise<void>;
11
- export declare const generateTree: (writer: AwesomeDataWriter, treeFilename: string, labels: string[], tests: AwesomeTestResult[]) => Promise<void>;
11
+ export declare const generateTree: (writer: AwesomeDataWriter, treeFilename: string, labels: string[], tests: AwesomeTestResult[], options?: {
12
+ appendTitlePath?: boolean;
13
+ }) => Promise<void>;
12
14
  export declare const generateEnvironmentJson: (writer: AwesomeDataWriter, env: EnvironmentItem[]) => Promise<void>;
13
15
  export declare const generateEnvirontmentsList: (writer: AwesomeDataWriter, store: AllureStore) => Promise<void>;
14
16
  export declare const generateVariables: (writer: AwesomeDataWriter, store: AllureStore) => Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import { compareBy, createBaseUrlScript, createFontLinkTag, createReportDataScript, createScriptTag, createStylesLinkTag, incrementStatistic, nullsLast, ordinal, } from "@allurereport/core-api";
2
- import { createTreeByLabels, createTreeByTitlePath, filterTree, preciseTreeLabels, sortTree, transformTree, } from "@allurereport/plugin-api";
2
+ import { createTreeByLabels, createTreeByLabelsAndTitlePath, createTreeByTitlePath, filterTree, preciseTreeLabels, sortTree, transformTree, } from "@allurereport/plugin-api";
3
3
  import { generateCharts, getPieChartValues } from "@allurereport/web-commons";
4
4
  import Handlebars from "handlebars";
5
5
  import { randomUUID } from "node:crypto";
@@ -115,11 +115,19 @@ export const generateTestEnvGroups = async (writer, groups) => {
115
115
  export const generateNav = async (writer, trs, filename = "nav.json") => {
116
116
  await writer.writeWidget(filename, trs.filter(({ hidden }) => !hidden).map(({ id }) => id));
117
117
  };
118
- export const generateTree = async (writer, treeFilename, labels, tests) => {
118
+ export const generateTree = async (writer, treeFilename, labels, tests, options) => {
119
119
  const visibleTests = tests.filter((test) => !test.hidden);
120
- const tree = labels.length
121
- ? buildTreeByLabels(visibleTests, labels)
122
- : buildTreeByTitlePath(visibleTests);
120
+ const { appendTitlePath } = options || {};
121
+ let tree;
122
+ if (labels.length === 0) {
123
+ tree = buildTreeByTitlePath(visibleTests);
124
+ }
125
+ else if (appendTitlePath && labels.length) {
126
+ tree = buildTreeByLabelsAndTitlePathCombined(visibleTests, labels);
127
+ }
128
+ else {
129
+ tree = buildTreeByLabels(visibleTests, labels);
130
+ }
123
131
  filterTree(tree, (leaf) => !leaf.hidden);
124
132
  sortTree(tree, nullsLast(compareBy("start", ordinal())));
125
133
  transformTree(tree, (leaf, idx) => ({ ...leaf, groupOrder: idx + 1 }));
@@ -140,10 +148,33 @@ const buildTreeByTitlePath = (tests) => {
140
148
  }
141
149
  }
142
150
  const treeByTitlePath = createTreeByTitlePath(testsWithTitlePath, leafFactory, undefined, (group, leaf) => incrementStatistic(group.statistic, leaf.status));
151
+ if (!testsWithoutTitlePath.length) {
152
+ return treeByTitlePath;
153
+ }
143
154
  const defaultLabels = preciseTreeLabels(["parentSuite", "suite", "subSuite"], testsWithoutTitlePath, ({ labels }) => labels.map(({ name }) => name));
144
- const treeByDefaultLabels = createTreeByLabels(testsWithoutTitlePath, defaultLabels, leafFactory, undefined, (group, leaf) => incrementStatistic(group.statistic, leaf.status));
145
- const mergedLeavesById = { ...treeByTitlePath.leavesById, ...treeByDefaultLabels.leavesById };
146
- const mergedGroupsById = { ...treeByTitlePath.groupsById, ...treeByDefaultLabels.groupsById };
155
+ let treeByDefaultLabels = null;
156
+ if (defaultLabels.length) {
157
+ treeByDefaultLabels = createTreeByLabelsAndTitlePath(testsWithoutTitlePath, defaultLabels, leafFactory, undefined, (group, leaf) => incrementStatistic(group.statistic, leaf.status));
158
+ }
159
+ else {
160
+ for (const test of testsWithoutTitlePath) {
161
+ const leaf = leafFactory(test);
162
+ treeByTitlePath.leavesById[leaf.nodeId] = leaf;
163
+ if (!treeByTitlePath.root.leaves) {
164
+ treeByTitlePath.root.leaves = [];
165
+ }
166
+ treeByTitlePath.root.leaves.push(leaf.nodeId);
167
+ }
168
+ return treeByTitlePath;
169
+ }
170
+ const mergedLeavesById = {
171
+ ...treeByTitlePath.leavesById,
172
+ ...treeByDefaultLabels.leavesById,
173
+ };
174
+ const mergedGroupsById = {
175
+ ...treeByTitlePath.groupsById,
176
+ ...treeByDefaultLabels.groupsById,
177
+ };
147
178
  const mergedRootLeaves = Array.from(new Set([...(treeByTitlePath.root.leaves ?? []), ...(treeByDefaultLabels.root.leaves ?? [])]));
148
179
  const mergedRootGroups = Array.from(new Set([...(treeByTitlePath.root.groups ?? []), ...(treeByDefaultLabels.root.groups ?? [])]));
149
180
  return {
@@ -155,6 +186,7 @@ const buildTreeByTitlePath = (tests) => {
155
186
  groupsById: mergedGroupsById,
156
187
  };
157
188
  };
189
+ const buildTreeByLabelsAndTitlePathCombined = (tests, labels) => createTreeByLabelsAndTitlePath(tests, labels, leafFactory, undefined, (group, leaf) => incrementStatistic(group.statistic, leaf.status));
158
190
  const leafFactory = ({ id, name, status, duration, flaky, start, transition, retry, retriesCount, }) => ({
159
191
  nodeId: id,
160
192
  name,
@@ -242,7 +274,7 @@ export const generateQualityGateResults = async (writer, qualityGateResults = []
242
274
  await writer.writeWidget("quality-gate.json", qualityGateResults);
243
275
  };
244
276
  export const generateStaticFiles = async (payload) => {
245
- const { id, reportName = "Allure Report", reportLanguage = "en", singleFile, logo = "", theme = "auto", groupBy, reportFiles, reportDataFiles, reportUuid, allureVersion, layout = "base", charts = [], defaultSection = "", ci, } = payload;
277
+ const { id, reportName = "Allure Report", reportLanguage = "en", singleFile, logo = "", theme = "auto", groupBy, reportFiles, reportDataFiles, reportUuid, allureVersion, layout = "base", charts = [], timeline, defaultSection = "", ci, } = payload;
246
278
  const compile = Handlebars.compile(template);
247
279
  const manifest = await readTemplateManifest(payload.singleFile);
248
280
  const headTags = [];
@@ -251,6 +283,9 @@ export const generateStaticFiles = async (payload) => {
251
283
  if (charts.length) {
252
284
  sections.push("charts");
253
285
  }
286
+ if (timeline) {
287
+ sections.push("timeline");
288
+ }
254
289
  if (!payload.singleFile) {
255
290
  for (const key in manifest) {
256
291
  const fileName = manifest[key];
package/dist/model.d.ts CHANGED
@@ -12,9 +12,13 @@ export type AwesomeOptions = {
12
12
  ci?: CiDescriptor;
13
13
  filter?: (testResult: TestResult) => boolean;
14
14
  charts?: ChartOptions[];
15
+ timeline?: {
16
+ minDuration?: number;
17
+ };
15
18
  sections?: string[];
16
19
  defaultSection?: string;
17
20
  publish?: boolean;
21
+ appendTitlePath?: boolean;
18
22
  };
19
23
  export type TemplateManifest = Record<string, string>;
20
24
  export type AwesomePluginOptions = AwesomeOptions;
package/dist/plugin.js CHANGED
@@ -15,6 +15,7 @@ import { convertToSummaryTestResult, } from "@allurereport/plugin-api";
15
15
  import { preciseTreeLabels } from "@allurereport/plugin-api";
16
16
  import { join } from "node:path";
17
17
  import { filterEnv } from "./environments.js";
18
+ import { generateTimeline } from "./generateTimeline.js";
18
19
  import { generateAllCharts, generateAttachmentsFiles, generateEnvironmentJson, generateEnvirontmentsList, generateGlobals, generateHistoryDataPoints, generateNav, generateQualityGateResults, generateStaticFiles, generateStatistic, generateTestCases, generateTestEnvGroups, generateTestResults, generateTree, generateVariables, } from "./generators.js";
19
20
  import { InMemoryReportDataWriter, ReportFileDataWriter } from "./writer.js";
20
21
  export class AwesomePlugin {
@@ -22,7 +23,7 @@ export class AwesomePlugin {
22
23
  this.options = options;
23
24
  _AwesomePlugin_writer.set(this, void 0);
24
25
  _AwesomePlugin_generate.set(this, async (context, store) => {
25
- const { singleFile, groupBy = [], filter } = this.options ?? {};
26
+ const { singleFile, groupBy = [], filter, appendTitlePath } = this.options ?? {};
26
27
  const environmentItems = await store.metadataByKey("allure_environment");
27
28
  const reportEnvironments = await store.allEnvironments();
28
29
  const attachments = await store.allAttachments();
@@ -44,6 +45,7 @@ export class AwesomePlugin {
44
45
  envs: environments,
45
46
  });
46
47
  await generateAllCharts(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, this.options, context);
48
+ await generateTimeline(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, this.options);
47
49
  const convertedTrs = await generateTestResults(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store, allTrs, this.options.filter);
48
50
  const hasGroupBy = groupBy.length > 0;
49
51
  const treeLabels = hasGroupBy
@@ -51,12 +53,14 @@ export class AwesomePlugin {
51
53
  : [];
52
54
  await generateHistoryDataPoints(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store);
53
55
  await generateTestCases(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), convertedTrs);
54
- await generateTree(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), "tree.json", treeLabels, convertedTrs);
56
+ await generateTree(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), "tree.json", treeLabels, convertedTrs, { appendTitlePath });
55
57
  await generateNav(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), convertedTrs, "nav.json");
56
58
  await generateTestEnvGroups(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), allTestEnvGroups);
57
59
  for (const reportEnvironment of reportEnvironments) {
58
60
  const envConvertedTrs = convertedTrs.filter(({ environment }) => environment === reportEnvironment);
59
- await generateTree(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), join(reportEnvironment, "tree.json"), treeLabels, envConvertedTrs);
61
+ await generateTree(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), join(reportEnvironment, "tree.json"), treeLabels, envConvertedTrs, {
62
+ appendTitlePath,
63
+ });
60
64
  await generateNav(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), envConvertedTrs, join(reportEnvironment, "nav.json"));
61
65
  }
62
66
  await generateEnvirontmentsList(__classPrivateFieldGet(this, _AwesomePlugin_writer, "f"), store);
@@ -122,6 +126,7 @@ export class AwesomePlugin {
122
126
  status: worstStatus ?? "passed",
123
127
  duration,
124
128
  createdAt,
129
+ withTestResultsLinks: true,
125
130
  plugin: "Awesome",
126
131
  newTests: newTrs.map(convertToSummaryTestResult),
127
132
  flakyTests: flakyTrs.map(convertToSummaryTestResult),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/plugin-awesome",
3
- "version": "3.0.0-beta.23",
3
+ "version": "3.0.0-beta.25",
4
4
  "description": "Allure Awesome Plugin – brand new HTML report with modern design and new features",
5
5
  "keywords": [
6
6
  "allure",
@@ -30,11 +30,11 @@
30
30
  "test": "rimraf ./out && vitest run"
31
31
  },
32
32
  "dependencies": {
33
- "@allurereport/charts-api": "3.0.0-beta.23",
34
- "@allurereport/core-api": "3.0.0-beta.23",
35
- "@allurereport/plugin-api": "3.0.0-beta.23",
36
- "@allurereport/web-awesome": "3.0.0-beta.23",
37
- "@allurereport/web-commons": "3.0.0-beta.23",
33
+ "@allurereport/charts-api": "3.0.0-beta.25",
34
+ "@allurereport/core-api": "3.0.0-beta.25",
35
+ "@allurereport/plugin-api": "3.0.0-beta.25",
36
+ "@allurereport/web-awesome": "3.0.0-beta.25",
37
+ "@allurereport/web-commons": "3.0.0-beta.25",
38
38
  "d3-shape": "^3.2.0",
39
39
  "handlebars": "^4.7.8"
40
40
  },