@allurereport/plugin-api 3.0.0-beta.10
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 +27 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.js +3 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +3 -0
- package/dist/plugin.d.ts +34 -0
- package/dist/plugin.js +1 -0
- package/dist/qualityGate.d.ts +44 -0
- package/dist/qualityGate.js +1 -0
- package/dist/resultFile.d.ts +12 -0
- package/dist/resultFile.js +1 -0
- package/dist/store.d.ts +32 -0
- package/dist/store.js +1 -0
- package/dist/utils/misc.d.ts +1 -0
- package/dist/utils/misc.js +2 -0
- package/dist/utils/tree.d.ts +10 -0
- package/dist/utils/tree.js +199 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Plugin API
|
|
2
|
+
|
|
3
|
+
> Collection of interfaces for Allure plugins
|
|
4
|
+
|
|
5
|
+
[<img src="https://allurereport.org/public/img/allure-report.svg" height="85px" alt="Allure Report logo" align="right" />](https://allurereport.org "Allure Report")
|
|
6
|
+
|
|
7
|
+
- Learn more about Allure Report at https://allurereport.org
|
|
8
|
+
- 📚 [Documentation](https://allurereport.org/docs/) – discover official documentation for Allure Report
|
|
9
|
+
- ❓ [Questions and Support](https://github.com/orgs/allure-framework/discussions/categories/questions-support) – get help from the team and community
|
|
10
|
+
- 📢 [Official announcements](https://github.com/orgs/allure-framework/discussions/categories/announcements) – be in touch with the latest updates
|
|
11
|
+
- 💬 [General Discussion ](https://github.com/orgs/allure-framework/discussions/categories/general-discussion) – engage in casual conversations, share insights and ideas with the community
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
The interfaces in the package describe the entities used for building Allure Plugins.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
Use your favorite package manager to install the package:
|
|
22
|
+
|
|
23
|
+
```shell
|
|
24
|
+
npm add @allurereport/plugin-api
|
|
25
|
+
yarn add @allurereport/plugin-api
|
|
26
|
+
pnpm add @allurereport/plugin-api
|
|
27
|
+
```
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DefaultLabelsConfig, EnvironmentsConfig, ReportVariables } from "@allurereport/core-api";
|
|
2
|
+
import type { PluginDescriptor } from "./plugin.js";
|
|
3
|
+
import type { QualityGateConfig } from "./qualityGate.js";
|
|
4
|
+
export interface Config {
|
|
5
|
+
name?: string;
|
|
6
|
+
output?: string;
|
|
7
|
+
historyPath?: string;
|
|
8
|
+
knownIssuesPath?: string;
|
|
9
|
+
defaultLabels?: DefaultLabelsConfig;
|
|
10
|
+
environments?: EnvironmentsConfig;
|
|
11
|
+
variables?: ReportVariables;
|
|
12
|
+
plugins?: Record<string, PluginDescriptor>;
|
|
13
|
+
qualityGate?: QualityGateConfig;
|
|
14
|
+
}
|
|
15
|
+
export declare const defineConfig: (allureConfig: Config) => Config;
|
package/dist/config.js
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AllureStore } from "./store.js";
|
|
2
|
+
export interface PluginDescriptor {
|
|
3
|
+
import?: string;
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
options?: Record<string, any>;
|
|
6
|
+
}
|
|
7
|
+
export interface ReportFiles {
|
|
8
|
+
addFile(path: string, data: Buffer): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export interface PluginState {
|
|
11
|
+
set(key: string, value: any): Promise<void>;
|
|
12
|
+
get(key: string): Promise<void>;
|
|
13
|
+
unset(key: string): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export interface PluginContext {
|
|
16
|
+
state: PluginState;
|
|
17
|
+
allureVersion: string;
|
|
18
|
+
reportUuid: string;
|
|
19
|
+
reportName: string;
|
|
20
|
+
reportFiles: ReportFiles;
|
|
21
|
+
}
|
|
22
|
+
export interface BatchOptions {
|
|
23
|
+
maxTimeout?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface Realtime {
|
|
26
|
+
onTestResults(listener: (trIds: string[]) => Promise<void>, options?: BatchOptions): void;
|
|
27
|
+
onTestFixtureResults(listener: (tfrIds: string[]) => Promise<void>, options?: BatchOptions): void;
|
|
28
|
+
onAttachmentFiles(listener: (afIds: string[]) => Promise<void>, options?: BatchOptions): void;
|
|
29
|
+
}
|
|
30
|
+
export interface Plugin {
|
|
31
|
+
start?(context: PluginContext, store: AllureStore, realtime: Realtime): Promise<void>;
|
|
32
|
+
update?(context: PluginContext, store: AllureStore): Promise<void>;
|
|
33
|
+
done?(context: PluginContext, store: AllureStore): Promise<void>;
|
|
34
|
+
}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { AllureStore } from "./store.js";
|
|
2
|
+
export type QualityGateRules = Record<string, any>;
|
|
3
|
+
export type QualityGateRulesBaseMeta<T> = {
|
|
4
|
+
type: T;
|
|
5
|
+
};
|
|
6
|
+
export type QualityGateLabelsRulesMeta = QualityGateRulesBaseMeta<"label"> & {
|
|
7
|
+
name: string;
|
|
8
|
+
value: string;
|
|
9
|
+
};
|
|
10
|
+
export type QualityGateParametersRulesMeta = QualityGateRulesBaseMeta<"parameter"> & {
|
|
11
|
+
name: string;
|
|
12
|
+
value: string;
|
|
13
|
+
};
|
|
14
|
+
export type QualityGateLabelsEnforceConfig = {
|
|
15
|
+
type: "label";
|
|
16
|
+
name: string;
|
|
17
|
+
value: string;
|
|
18
|
+
rules: QualityGateRules;
|
|
19
|
+
};
|
|
20
|
+
export type QualityGateParametersEnforceConfig = {
|
|
21
|
+
type: "parameter";
|
|
22
|
+
name: string;
|
|
23
|
+
value: string;
|
|
24
|
+
rules: QualityGateRules;
|
|
25
|
+
};
|
|
26
|
+
export type QualityGateRulesMeta = Omit<QualityGateLabelsRulesMeta, "rules"> | Omit<QualityGateParametersRulesMeta, "rules">;
|
|
27
|
+
export type QualityGateEnforceConfig = QualityGateLabelsEnforceConfig | QualityGateParametersEnforceConfig;
|
|
28
|
+
export type QualityGateValidationResult = {
|
|
29
|
+
success: boolean;
|
|
30
|
+
rule: string;
|
|
31
|
+
meta?: QualityGateRulesMeta;
|
|
32
|
+
expected?: number;
|
|
33
|
+
actual?: number;
|
|
34
|
+
message?: string;
|
|
35
|
+
};
|
|
36
|
+
export interface QualityGateValidator {
|
|
37
|
+
validate(store: AllureStore): Promise<QualityGateValidationResult>;
|
|
38
|
+
}
|
|
39
|
+
export type QualityGateValidatorConstructor = new (limit: number, meta?: QualityGateRulesMeta) => QualityGateValidator;
|
|
40
|
+
export type QualityGateConfig = {
|
|
41
|
+
rules?: QualityGateRules;
|
|
42
|
+
enforce?: QualityGateEnforceConfig[];
|
|
43
|
+
validators?: Record<string, QualityGateValidatorConstructor>;
|
|
44
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
2
|
+
export interface ResultFile {
|
|
3
|
+
readContent: <T>(transform: (stream: Readable) => Promise<T | undefined>) => Promise<T | undefined>;
|
|
4
|
+
getOriginalFileName: () => string;
|
|
5
|
+
getExtension: () => string;
|
|
6
|
+
getContentType: () => string | undefined;
|
|
7
|
+
getContentLength: () => number | undefined;
|
|
8
|
+
asJson: <T>() => Promise<T | undefined>;
|
|
9
|
+
asUtf8String: () => Promise<string | undefined>;
|
|
10
|
+
asBuffer: () => Promise<Buffer | undefined>;
|
|
11
|
+
writeTo: (path: string) => Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AttachmentLink, HistoryDataPoint, HistoryTestResult, KnownTestFailure, Statistic, TestCase, TestFixtureResult, TestResult } from "@allurereport/core-api";
|
|
2
|
+
import type { ResultFile } from "./resultFile.js";
|
|
3
|
+
export interface AllureStore {
|
|
4
|
+
allTestCases: () => Promise<TestCase[]>;
|
|
5
|
+
allTestResults: (options?: {
|
|
6
|
+
includeHidden: boolean;
|
|
7
|
+
}) => Promise<TestResult[]>;
|
|
8
|
+
allAttachments: () => Promise<AttachmentLink[]>;
|
|
9
|
+
allMetadata: () => Promise<Record<string, any>>;
|
|
10
|
+
allFixtures: () => Promise<TestFixtureResult[]>;
|
|
11
|
+
allHistoryDataPoints: () => Promise<HistoryDataPoint[]>;
|
|
12
|
+
allKnownIssues: () => Promise<KnownTestFailure[]>;
|
|
13
|
+
testCaseById: (tcId: string) => Promise<TestCase | undefined>;
|
|
14
|
+
testResultById: (trId: string) => Promise<TestResult | undefined>;
|
|
15
|
+
attachmentById: (attachmentId: string) => Promise<AttachmentLink | undefined>;
|
|
16
|
+
attachmentContentById: (attachmentId: string) => Promise<ResultFile | undefined>;
|
|
17
|
+
metadataByKey: <T>(key: string) => Promise<T | undefined>;
|
|
18
|
+
testResultsByTcId: (tcId: string) => Promise<TestResult[]>;
|
|
19
|
+
attachmentsByTrId: (trId: string) => Promise<AttachmentLink[]>;
|
|
20
|
+
retriesByTrId: (trId: string) => Promise<TestResult[]>;
|
|
21
|
+
historyByTrId: (trId: string) => Promise<HistoryTestResult[]>;
|
|
22
|
+
fixturesByTrId: (trId: string) => Promise<TestFixtureResult[]>;
|
|
23
|
+
failedTestResults: () => Promise<TestResult[]>;
|
|
24
|
+
unknownFailedTestResults: () => Promise<TestResult[]>;
|
|
25
|
+
testResultsByLabel: (labelName: string) => Promise<{
|
|
26
|
+
_: TestResult[];
|
|
27
|
+
[x: string]: TestResult[];
|
|
28
|
+
}>;
|
|
29
|
+
testsStatistic: (filter?: (testResult: TestResult) => boolean) => Promise<Statistic>;
|
|
30
|
+
allEnvironments: () => Promise<string[]>;
|
|
31
|
+
testResultsByEnvironment: (env: string) => Promise<TestResult[]>;
|
|
32
|
+
}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const md5: (data: string) => string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Comparator, type DefaultTreeGroup, type DefaultTreeLeaf, type TestResult, type TreeData, type TreeGroup, type TreeLeaf } from "@allurereport/core-api";
|
|
2
|
+
export declare const byLabels: (item: TestResult, labelNames: string[]) => string[][];
|
|
3
|
+
export declare const filterTreeLabels: (data: TestResult[], labelNames: string[]) => string[];
|
|
4
|
+
export declare const createTreeByLabels: <T = TestResult, L = DefaultTreeLeaf, G = DefaultTreeGroup>(data: T[], labelNames: string[], leafFactory?: (item: T) => TreeLeaf<L>, groupFactory?: (parentGroup: string | undefined, groupClassifier: string) => TreeGroup<G>, addLeafToGroup?: (group: TreeGroup<G>, leaf: TreeLeaf<L>) => void) => TreeData<L, G>;
|
|
5
|
+
export declare const createTreeByCategories: <T = TestResult, L = DefaultTreeLeaf, G = DefaultTreeGroup>(data: T[], leafFactory?: (item: T) => TreeLeaf<L>, groupFactory?: (parentGroup: string | undefined, groupClassifier: string) => TreeGroup<G>, addLeafToGroup?: (group: TreeGroup<G>, leaf: TreeLeaf<L>) => void) => TreeData<L, G>;
|
|
6
|
+
export declare const byCategories: (item: TestResult) => string[][];
|
|
7
|
+
export declare const preciseTreeLabels: <T = TestResult>(labelNames: string[], trs: T[], labelNamesAccessor?: (tr: T) => string[]) => string[];
|
|
8
|
+
export declare const filterTree: <L, G>(tree: TreeData<L, G>, predicate: (leaf: TreeLeaf<L>) => boolean) => TreeData<L, G>;
|
|
9
|
+
export declare const sortTree: <L, G>(tree: TreeData<L, G>, comparator: Comparator<TreeLeaf<L>>) => TreeData<L, G>;
|
|
10
|
+
export declare const transformTree: <L, G>(tree: TreeData<L, G>, transformer: (leaf: TreeLeaf<L>, idx: number) => TreeLeaf<L>) => TreeData<L, G>;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { findByLabelName, } from "@allurereport/core-api";
|
|
2
|
+
import { emptyStatistic } from "@allurereport/core-api";
|
|
3
|
+
import { md5 } from "./misc.js";
|
|
4
|
+
const addLeaf = (node, nodeId) => {
|
|
5
|
+
if (node.leaves === undefined) {
|
|
6
|
+
node.leaves = [];
|
|
7
|
+
}
|
|
8
|
+
if (node.leaves.find((value) => value === nodeId)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
node.leaves.push(nodeId);
|
|
12
|
+
};
|
|
13
|
+
const addGroup = (node, nodeId) => {
|
|
14
|
+
if (node.groups === undefined) {
|
|
15
|
+
node.groups = [];
|
|
16
|
+
}
|
|
17
|
+
if (node.groups.find((value) => value === nodeId)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
node.groups.push(nodeId);
|
|
21
|
+
};
|
|
22
|
+
const createTree = (data, classifier, leafFactory, groupFactory, addLeafToGroup = () => { }) => {
|
|
23
|
+
const groupsByClassifier = {};
|
|
24
|
+
const leavesById = {};
|
|
25
|
+
const groupsById = {};
|
|
26
|
+
const root = { groups: [], leaves: [] };
|
|
27
|
+
for (const item of data) {
|
|
28
|
+
const leaf = leafFactory(item);
|
|
29
|
+
leavesById[leaf.nodeId] = leaf;
|
|
30
|
+
const itemGroups = classifier(item);
|
|
31
|
+
let parentGroups = [root];
|
|
32
|
+
for (const layer of itemGroups) {
|
|
33
|
+
if (layer.length === 0) {
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
parentGroups = layer.flatMap((group) => {
|
|
37
|
+
return parentGroups.map((parentGroup) => {
|
|
38
|
+
const parentId = "nodeId" in parentGroup ? parentGroup.nodeId : "";
|
|
39
|
+
if (groupsByClassifier[parentId] === undefined) {
|
|
40
|
+
groupsByClassifier[parentId] = {};
|
|
41
|
+
}
|
|
42
|
+
if (groupsByClassifier[parentId][group] === undefined) {
|
|
43
|
+
const newGroup = groupFactory(parentId, group);
|
|
44
|
+
groupsByClassifier[parentId][group] = newGroup;
|
|
45
|
+
groupsById[newGroup.nodeId] = newGroup;
|
|
46
|
+
}
|
|
47
|
+
const currentGroup = groupsByClassifier[parentId][group];
|
|
48
|
+
addGroup(parentGroup, currentGroup.nodeId);
|
|
49
|
+
addLeafToGroup(currentGroup, leaf);
|
|
50
|
+
return currentGroup;
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
parentGroups.forEach((parentGroup) => addLeaf(parentGroup, leaf.nodeId));
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
root,
|
|
58
|
+
groupsById,
|
|
59
|
+
leavesById,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export const byLabels = (item, labelNames) => {
|
|
63
|
+
return labelNames.map((labelName) => item.labels.filter((label) => labelName === label.name).map((label) => label.value ?? "__unknown") ?? []);
|
|
64
|
+
};
|
|
65
|
+
export const filterTreeLabels = (data, labelNames) => {
|
|
66
|
+
return [...labelNames]
|
|
67
|
+
.reverse()
|
|
68
|
+
.filter((labelName) => data.find((item) => findByLabelName(item.labels, labelName)))
|
|
69
|
+
.reverse();
|
|
70
|
+
};
|
|
71
|
+
export const createTreeByLabels = (data, labelNames, leafFactory, groupFactory, addLeafToGroup = () => { }) => {
|
|
72
|
+
const leafFactoryFn = leafFactory ??
|
|
73
|
+
((tr) => {
|
|
74
|
+
const { id, name, status, duration } = tr;
|
|
75
|
+
return {
|
|
76
|
+
nodeId: id,
|
|
77
|
+
name,
|
|
78
|
+
status,
|
|
79
|
+
duration,
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
const groupFactoryFn = groupFactory ??
|
|
83
|
+
((parentId, groupClassifier) => ({
|
|
84
|
+
nodeId: md5((parentId ? `${parentId}.` : "") + groupClassifier),
|
|
85
|
+
name: groupClassifier,
|
|
86
|
+
statistic: emptyStatistic(),
|
|
87
|
+
}));
|
|
88
|
+
return createTree(data, (item) => byLabels(item, labelNames), leafFactoryFn, groupFactoryFn, addLeafToGroup);
|
|
89
|
+
};
|
|
90
|
+
export const createTreeByCategories = (data, leafFactory, groupFactory, addLeafToGroup = () => { }) => {
|
|
91
|
+
const leafFactoryFn = leafFactory ??
|
|
92
|
+
((tr) => {
|
|
93
|
+
const { id, name, status, duration } = tr;
|
|
94
|
+
return {
|
|
95
|
+
nodeId: id,
|
|
96
|
+
name,
|
|
97
|
+
status,
|
|
98
|
+
duration,
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
const groupFactoryFn = groupFactory ??
|
|
102
|
+
((parentId, groupClassifier) => ({
|
|
103
|
+
nodeId: md5((parentId ? `${parentId}.` : "") + groupClassifier),
|
|
104
|
+
name: groupClassifier,
|
|
105
|
+
statistic: emptyStatistic(),
|
|
106
|
+
}));
|
|
107
|
+
return createTree(data, (item) => byCategories(item), leafFactoryFn, groupFactoryFn, addLeafToGroup);
|
|
108
|
+
};
|
|
109
|
+
export const byCategories = (item) => {
|
|
110
|
+
return [item.categories?.map((category) => category.name)];
|
|
111
|
+
};
|
|
112
|
+
export const preciseTreeLabels = (labelNames, trs, labelNamesAccessor = (tr) => tr.labels.map(({ name }) => name)) => {
|
|
113
|
+
const result = new Set();
|
|
114
|
+
for (const labelName of labelNames) {
|
|
115
|
+
if (trs.some((tr) => labelNamesAccessor(tr).includes(labelName))) {
|
|
116
|
+
result.add(labelName);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return Array.from(result);
|
|
120
|
+
};
|
|
121
|
+
export const filterTree = (tree, predicate) => {
|
|
122
|
+
const visitedGroups = new Set();
|
|
123
|
+
const { root, leavesById, groupsById } = tree;
|
|
124
|
+
const filterGroupLeaves = (group) => {
|
|
125
|
+
if (!predicate) {
|
|
126
|
+
return group;
|
|
127
|
+
}
|
|
128
|
+
if (group.groups?.length) {
|
|
129
|
+
group.groups.forEach((groupId) => {
|
|
130
|
+
const subGroup = groupsById[groupId];
|
|
131
|
+
if (!subGroup || visitedGroups.has(groupId)) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
filterGroupLeaves(subGroup);
|
|
135
|
+
visitedGroups.add(groupId);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (group.leaves?.length) {
|
|
139
|
+
group.leaves = group.leaves.filter((leaveId) => predicate(leavesById[leaveId]));
|
|
140
|
+
}
|
|
141
|
+
return group;
|
|
142
|
+
};
|
|
143
|
+
filterGroupLeaves(root);
|
|
144
|
+
return tree;
|
|
145
|
+
};
|
|
146
|
+
export const sortTree = (tree, comparator) => {
|
|
147
|
+
const visitedGroups = new Set();
|
|
148
|
+
const { root, leavesById, groupsById } = tree;
|
|
149
|
+
const sortGroupLeaves = (group) => {
|
|
150
|
+
if (!comparator) {
|
|
151
|
+
return group;
|
|
152
|
+
}
|
|
153
|
+
if (group.groups?.length) {
|
|
154
|
+
group.groups.forEach((groupId) => {
|
|
155
|
+
if (visitedGroups.has(groupId)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
sortGroupLeaves(groupsById[groupId]);
|
|
159
|
+
visitedGroups.add(groupId);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (group.leaves?.length) {
|
|
163
|
+
group.leaves = group.leaves.sort((a, b) => {
|
|
164
|
+
const leafA = leavesById[a];
|
|
165
|
+
const leafB = leavesById[b];
|
|
166
|
+
return comparator(leafA, leafB);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return group;
|
|
170
|
+
};
|
|
171
|
+
sortGroupLeaves(root);
|
|
172
|
+
return tree;
|
|
173
|
+
};
|
|
174
|
+
export const transformTree = (tree, transformer) => {
|
|
175
|
+
const visitedGroups = new Set();
|
|
176
|
+
const { root, leavesById, groupsById } = tree;
|
|
177
|
+
const transformGroupLeaves = (group) => {
|
|
178
|
+
if (!transformer) {
|
|
179
|
+
return group;
|
|
180
|
+
}
|
|
181
|
+
if (group.groups?.length) {
|
|
182
|
+
group.groups.forEach((groupId) => {
|
|
183
|
+
if (visitedGroups.has(groupId)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
transformGroupLeaves(groupsById[groupId]);
|
|
187
|
+
visitedGroups.add(groupId);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (group.leaves?.length) {
|
|
191
|
+
group.leaves.forEach((leaf, i) => {
|
|
192
|
+
leavesById[leaf] = transformer(leavesById[leaf], i);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return group;
|
|
196
|
+
};
|
|
197
|
+
transformGroupLeaves(root);
|
|
198
|
+
return tree;
|
|
199
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@allurereport/plugin-api",
|
|
3
|
+
"version": "3.0.0-beta.10",
|
|
4
|
+
"description": "Allure Plugin API",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"allure"
|
|
7
|
+
],
|
|
8
|
+
"repository": "https://github.com/allure-framework/allure3",
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"author": "Qameta Software",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"module": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "run clean && tsc --project ./tsconfig.json",
|
|
23
|
+
"clean": "rimraf ./dist",
|
|
24
|
+
"eslint": "eslint ./src/**/*.{js,jsx,ts,tsx}",
|
|
25
|
+
"eslint:format": "eslint --fix ./src/**/*.{js,jsx,ts,tsx}",
|
|
26
|
+
"test": "rimraf ./out && vitest run"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@allurereport/core-api": "3.0.0-beta.10"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@stylistic/eslint-plugin": "^2.6.1",
|
|
33
|
+
"@types/eslint": "^8.56.11",
|
|
34
|
+
"@types/node": "^20.17.9",
|
|
35
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
36
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
37
|
+
"@vitest/runner": "^2.1.8",
|
|
38
|
+
"@vitest/snapshot": "^2.1.8",
|
|
39
|
+
"allure-vitest": "^3.0.9",
|
|
40
|
+
"eslint": "^8.57.0",
|
|
41
|
+
"eslint-config-prettier": "^9.1.0",
|
|
42
|
+
"eslint-plugin-import": "^2.29.1",
|
|
43
|
+
"eslint-plugin-jsdoc": "^50.0.0",
|
|
44
|
+
"eslint-plugin-n": "^17.10.1",
|
|
45
|
+
"eslint-plugin-no-null": "^1.0.2",
|
|
46
|
+
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
47
|
+
"rimraf": "^6.0.1",
|
|
48
|
+
"typescript": "^5.6.3",
|
|
49
|
+
"vitest": "^2.1.8"
|
|
50
|
+
}
|
|
51
|
+
}
|