@allurereport/plugin-api
Advanced tools
+2
-4
@@ -1,2 +0,2 @@ | ||
| import type { CategoriesConfig, DefaultLabelsConfig, EnvironmentsConfig, ReportVariables } from "@allurereport/core-api"; | ||
| import type { AllureServiceConfig, CategoriesConfig, DefaultLabelsConfig, EnvironmentsConfig, ReportVariables } from "@allurereport/core-api"; | ||
| import type { PluginDescriptor } from "./plugin.js"; | ||
@@ -22,5 +22,3 @@ import type { QualityGateConfig } from "./qualityGate.js"; | ||
| qualityGate?: QualityGateConfig; | ||
| allureService?: { | ||
| accessToken?: string; | ||
| }; | ||
| allureService?: AllureServiceConfig; | ||
| categories?: CategoriesConfig; | ||
@@ -27,0 +25,0 @@ globalAttachments?: string[]; |
+22
-1
@@ -1,2 +0,2 @@ | ||
| import type { AllureHistory, AttachmentLink, CategoryDefinition, CiDescriptor, Statistic, TestError, TestResult, TestStatus } from "@allurereport/core-api"; | ||
| import type { AllureHistory, AttachmentLink, CategoryDefinition, CiDescriptor, HistoryDataPoint, Statistic, TestError, TestResult, TestStatus } from "@allurereport/core-api"; | ||
| import type { QualityGateValidationResult } from "./qualityGate.js"; | ||
@@ -28,2 +28,3 @@ import type { ResultFile } from "./resultFile.js"; | ||
| reportUrl?: string; | ||
| realTime?: boolean; | ||
| output: string; | ||
@@ -52,2 +53,22 @@ ci?: CiDescriptor; | ||
| } | ||
| export interface PluginReportFile { | ||
| pluginId: string; | ||
| publish: boolean; | ||
| files: Record<string, string>; | ||
| } | ||
| export interface PluginPublishContext { | ||
| reportUuid: string; | ||
| reportName: string; | ||
| ci?: CiDescriptor; | ||
| historyPoint?: HistoryDataPoint; | ||
| reports: PluginReportFile[]; | ||
| summary?: { | ||
| filepath: string; | ||
| summaries?: PluginSummary[]; | ||
| }; | ||
| } | ||
| export interface PluginPublishResult { | ||
| linksByPluginId: Record<string, string>; | ||
| remoteHref?: string; | ||
| } | ||
| export interface ExitCode { | ||
@@ -54,0 +75,0 @@ actual?: number; |
+13
-6
@@ -6,6 +6,12 @@ import type { AllureCheckResult, AttachmentLink, EnvironmentIdentity, HistoryDataPoint, HistoryTestResult, KnownTestFailure, ReportVariables, Statistic, TestCase, TestEnvGroup, TestError, TestFixtureResult, TestResult } from "@allurereport/core-api"; | ||
| export type TestResultFilter = (testResult: TestResult) => boolean; | ||
| export interface TestResultRelatedData { | ||
| attachmentsByTrId: Map<string, AttachmentLink[]>; | ||
| fixturesByTrId: Map<string, TestFixtureResult[]>; | ||
| historyByTrId: Map<string, HistoryTestResult[] | undefined>; | ||
| retriesByTrId: Map<string, TestResult[]>; | ||
| } | ||
| export interface AllureStore { | ||
| allTestCases: () => Promise<TestCase[]>; | ||
| allTestResults: (options?: { | ||
| includeHidden?: boolean; | ||
| includeRetries?: boolean; | ||
| filter?: TestResultFilter; | ||
@@ -43,2 +49,3 @@ }) => Promise<TestResult[]>; | ||
| fixturesByTrId: (trId: string) => Promise<TestFixtureResult[]>; | ||
| relatedByTestResultIds: (trIds: readonly string[]) => Promise<TestResultRelatedData>; | ||
| failedTestResults: () => Promise<TestResult[]>; | ||
@@ -54,6 +61,6 @@ unknownFailedTestResults: () => Promise<TestResult[]>; | ||
| testResultsByEnvironment: (env: string, options?: { | ||
| includeHidden?: boolean; | ||
| includeRetries?: boolean; | ||
| }) => Promise<TestResult[]>; | ||
| testResultsByEnvironmentId: (envId: string, options?: { | ||
| includeHidden?: boolean; | ||
| includeRetries?: boolean; | ||
| }) => Promise<TestResult[]>; | ||
@@ -79,6 +86,6 @@ allTestEnvGroups: () => Promise<TestEnvGroup[]>; | ||
| indexTestResultByTestCase: Record<string, string[]>; | ||
| indexLatestEnvTestResultByHistoryId: Record<string, string> | Record<string, Record<string, string>>; | ||
| indexAttachmentByFixture: Record<string, string[]>; | ||
| indexFixturesByTestResult: Record<string, string[]>; | ||
| indexKnownByHistoryId: Record<string, KnownTestFailure[]>; | ||
| testResultIdsIngestOrder: string[]; | ||
| } | ||
@@ -98,7 +105,7 @@ export declare enum AllureStoreDumpFiles { | ||
| IndexTestResultsByTestCase = "index-test-results-by-test-case.json", | ||
| IndexLatestEnvTestResultsByHistoryId = "index-latest-env-test-results-by-history-id.json", | ||
| IndexAttachmentsByFixture = "index-attachments-by-fixture.json", | ||
| IndexFixturesByTestResult = "index-fixtures-by-test-result.json", | ||
| IndexKnownByHistoryId = "index-known-by-history-id.json", | ||
| QualityGateResults = "quality-gate-results.json" | ||
| QualityGateResults = "quality-gate-results.json", | ||
| TestResultIngestOrder = "test-result-ingest-order.json" | ||
| } |
+1
-1
@@ -15,3 +15,2 @@ export var AllureStoreDumpFiles; | ||
| AllureStoreDumpFiles["IndexTestResultsByTestCase"] = "index-test-results-by-test-case.json"; | ||
| AllureStoreDumpFiles["IndexLatestEnvTestResultsByHistoryId"] = "index-latest-env-test-results-by-history-id.json"; | ||
| AllureStoreDumpFiles["IndexAttachmentsByFixture"] = "index-attachments-by-fixture.json"; | ||
@@ -21,2 +20,3 @@ AllureStoreDumpFiles["IndexFixturesByTestResult"] = "index-fixtures-by-test-result.json"; | ||
| AllureStoreDumpFiles["QualityGateResults"] = "quality-gate-results.json"; | ||
| AllureStoreDumpFiles["TestResultIngestOrder"] = "test-result-ingest-order.json"; | ||
| })(AllureStoreDumpFiles || (AllureStoreDumpFiles = {})); |
@@ -8,2 +8,7 @@ import { type Comparator, type DefaultTreeGroup, type DefaultTreeLeaf, type TestResult, type TreeData, type TreeGroup, type TreeLeaf } from "@allurereport/core-api"; | ||
| export declare const preciseTreeLabels: <T = TestResult>(labelNames: string[], trs: T[], labelNamesAccessor?: (tr: T) => string[]) => string[]; | ||
| export declare const processTree: <L, G>(tree: TreeData<L, G>, options: { | ||
| filter?: (leaf: TreeLeaf<L>) => boolean; | ||
| sort?: Comparator<TreeLeaf<L>>; | ||
| transform?: (leaf: TreeLeaf<L>, idx: number) => TreeLeaf<L>; | ||
| }) => TreeData<L, G>; | ||
| export declare const filterTree: <L, G>(tree: TreeData<L, G>, predicate: (leaf: TreeLeaf<L>) => boolean) => TreeData<L, G>; | ||
@@ -10,0 +15,0 @@ export declare const sortTree: <L, G>(tree: TreeData<L, G>, comparator: Comparator<TreeLeaf<L>>) => TreeData<L, G>; |
+106
-99
@@ -1,26 +0,39 @@ | ||
| import { createDictionary, findByLabelName, } from "@allurereport/core-api"; | ||
| import { emptyStatistic } from "@allurereport/core-api"; | ||
| import { md5 } from "./misc.js"; | ||
| const addLeaf = (node, nodeId) => { | ||
| const addLeaf = (childLeaves, node, nodeId) => { | ||
| if (node.leaves === undefined) { | ||
| node.leaves = []; | ||
| } | ||
| if (node.leaves.find((value) => value === nodeId)) { | ||
| let leaves = childLeaves.get(node); | ||
| if (!leaves) { | ||
| leaves = new Set(node.leaves); | ||
| childLeaves.set(node, leaves); | ||
| } | ||
| if (leaves.has(nodeId)) { | ||
| return; | ||
| } | ||
| leaves.add(nodeId); | ||
| node.leaves.push(nodeId); | ||
| }; | ||
| const addGroup = (node, nodeId) => { | ||
| const addGroup = (childGroups, node, nodeId) => { | ||
| if (node.groups === undefined) { | ||
| node.groups = []; | ||
| } | ||
| if (node.groups.find((value) => value === nodeId)) { | ||
| let groups = childGroups.get(node); | ||
| if (!groups) { | ||
| groups = new Set(node.groups); | ||
| childGroups.set(node, groups); | ||
| } | ||
| if (groups.has(nodeId)) { | ||
| return; | ||
| } | ||
| groups.add(nodeId); | ||
| node.groups.push(nodeId); | ||
| }; | ||
| const createTree = (data, classifier, leafFactory, groupFactory, addLeafToGroup = () => { }) => { | ||
| const groupsByClassifier = createDictionary(); | ||
| const groupsByClassifier = new Map(); | ||
| const leavesById = {}; | ||
| const groupsById = {}; | ||
| const childLeaves = new WeakMap(); | ||
| const childGroups = new WeakMap(); | ||
| const root = { groups: [], leaves: [] }; | ||
@@ -36,28 +49,36 @@ for (const item of data) { | ||
| } | ||
| parentGroups = layer.flatMap((group) => { | ||
| return parentGroups.flatMap((parentGroup) => { | ||
| const nextParentGroups = []; | ||
| const nextParentGroupIds = new Set(); | ||
| for (const group of layer) { | ||
| for (const parentGroup of parentGroups) { | ||
| const parentId = "nodeId" in parentGroup ? parentGroup.nodeId : ""; | ||
| if (groupsByClassifier[parentId] === undefined) { | ||
| groupsByClassifier[parentId] = createDictionary(); | ||
| let groupsByParent = groupsByClassifier.get(parentId); | ||
| if (groupsByParent === undefined) { | ||
| groupsByParent = new Map(); | ||
| groupsByClassifier.set(parentId, groupsByParent); | ||
| } | ||
| if (groupsByClassifier[parentId][group] === undefined) { | ||
| if (groupsByParent.get(group) === undefined) { | ||
| const newGroup = groupFactory(parentId, group); | ||
| if (!newGroup || typeof newGroup !== "object" || typeof newGroup.nodeId !== "string") { | ||
| return []; | ||
| continue; | ||
| } | ||
| groupsByClassifier[parentId][group] = newGroup; | ||
| groupsByParent.set(group, newGroup); | ||
| groupsById[newGroup.nodeId] = newGroup; | ||
| } | ||
| const currentGroup = groupsByClassifier[parentId][group]; | ||
| const currentGroup = groupsByParent.get(group); | ||
| if (!currentGroup || typeof currentGroup !== "object") { | ||
| return []; | ||
| continue; | ||
| } | ||
| addGroup(parentGroup, currentGroup.nodeId); | ||
| addGroup(childGroups, parentGroup, currentGroup.nodeId); | ||
| addLeafToGroup(currentGroup, leaf); | ||
| return [currentGroup]; | ||
| }); | ||
| }); | ||
| if (!nextParentGroupIds.has(currentGroup.nodeId)) { | ||
| nextParentGroupIds.add(currentGroup.nodeId); | ||
| nextParentGroups.push(currentGroup); | ||
| } | ||
| } | ||
| } | ||
| parentGroups = nextParentGroups; | ||
| } | ||
| parentGroups.forEach((parentGroup) => { | ||
| addLeaf(parentGroup, leaf.nodeId); | ||
| addLeaf(childLeaves, parentGroup, leaf.nodeId); | ||
| }); | ||
@@ -71,12 +92,26 @@ } | ||
| }; | ||
| export const byLabels = (item, labelNames) => { | ||
| return labelNames | ||
| .map((labelName) => item.labels.filter((label) => labelName === label.name).map((label) => label.value ?? "__unknown") ?? []) | ||
| .filter((layer) => layer.length > 0); | ||
| const byLabelsWithFallback = (item, labelNames, fallbackValue) => { | ||
| const labelsByName = new Map(); | ||
| for (const label of item.labels) { | ||
| const values = labelsByName.get(label.name) ?? []; | ||
| values.push(label.value ?? fallbackValue); | ||
| labelsByName.set(label.name, values); | ||
| } | ||
| return labelNames.map((labelName) => labelsByName.get(labelName) ?? []).filter((layer) => layer.length > 0); | ||
| }; | ||
| export const byLabels = (item, labelNames) => byLabelsWithFallback(item, labelNames, "__unknown"); | ||
| export const filterTreeLabels = (data, labelNames) => { | ||
| return [...labelNames] | ||
| .reverse() | ||
| .filter((labelName) => data.find((item) => findByLabelName(item.labels, labelName))) | ||
| .reverse(); | ||
| const requested = new Set(labelNames); | ||
| const found = new Set(); | ||
| for (const item of data) { | ||
| for (const label of item.labels) { | ||
| if (requested.has(label.name)) { | ||
| found.add(label.name); | ||
| } | ||
| } | ||
| if (found.size === requested.size) { | ||
| break; | ||
| } | ||
| } | ||
| return labelNames.filter((labelName) => found.has(labelName)); | ||
| }; | ||
@@ -133,17 +168,27 @@ export const createTreeByLabels = (data, labelNames, leafFactory, groupFactory, addLeafToGroup = () => { }) => { | ||
| export const preciseTreeLabels = (labelNames, trs, labelNamesAccessor = (tr) => tr.labels.map(({ name }) => name)) => { | ||
| const result = new Set(); | ||
| for (const labelName of labelNames) { | ||
| if (trs.some((tr) => labelNamesAccessor(tr).includes(labelName))) { | ||
| result.add(labelName); | ||
| const requested = new Set(labelNames); | ||
| const found = new Set(); | ||
| for (const tr of trs) { | ||
| for (const labelName of labelNamesAccessor(tr)) { | ||
| if (requested.has(labelName)) { | ||
| found.add(labelName); | ||
| } | ||
| } | ||
| if (found.size === requested.size) { | ||
| break; | ||
| } | ||
| } | ||
| return Array.from(result); | ||
| const emitted = new Set(); | ||
| return labelNames.filter((labelName) => { | ||
| if (!found.has(labelName) || emitted.has(labelName)) { | ||
| return false; | ||
| } | ||
| emitted.add(labelName); | ||
| return true; | ||
| }); | ||
| }; | ||
| export const filterTree = (tree, predicate) => { | ||
| export const processTree = (tree, options) => { | ||
| const visitedGroups = new Set(); | ||
| const { root, leavesById, groupsById } = tree; | ||
| const filterGroupLeaves = (group) => { | ||
| if (!predicate) { | ||
| return group; | ||
| } | ||
| const processGroup = (group) => { | ||
| if (group.groups?.length) { | ||
@@ -155,3 +200,3 @@ group.groups.forEach((groupId) => { | ||
| } | ||
| filterGroupLeaves(subGroup); | ||
| processGroup(subGroup); | ||
| visitedGroups.add(groupId); | ||
@@ -161,62 +206,31 @@ }); | ||
| if (group.leaves?.length) { | ||
| group.leaves = group.leaves.filter((leaveId) => predicate(leavesById[leaveId])); | ||
| if (options.filter) { | ||
| group.leaves = group.leaves.filter((leaveId) => options.filter(leavesById[leaveId])); | ||
| } | ||
| if (options.sort) { | ||
| group.leaves = group.leaves.sort((a, b) => { | ||
| const leafA = leavesById[a]; | ||
| const leafB = leavesById[b]; | ||
| return options.sort(leafA, leafB); | ||
| }); | ||
| } | ||
| if (options.transform) { | ||
| group.leaves.forEach((leafId, i) => { | ||
| leavesById[leafId] = options.transform(leavesById[leafId], i); | ||
| }); | ||
| } | ||
| } | ||
| return group; | ||
| }; | ||
| filterGroupLeaves(root); | ||
| processGroup(root); | ||
| return tree; | ||
| }; | ||
| export const filterTree = (tree, predicate) => { | ||
| return processTree(tree, { filter: predicate }); | ||
| }; | ||
| export const sortTree = (tree, comparator) => { | ||
| const visitedGroups = new Set(); | ||
| const { root, leavesById, groupsById } = tree; | ||
| const sortGroupLeaves = (group) => { | ||
| if (!comparator) { | ||
| return group; | ||
| } | ||
| if (group.groups?.length) { | ||
| group.groups.forEach((groupId) => { | ||
| if (visitedGroups.has(groupId)) { | ||
| return; | ||
| } | ||
| sortGroupLeaves(groupsById[groupId]); | ||
| visitedGroups.add(groupId); | ||
| }); | ||
| } | ||
| if (group.leaves?.length) { | ||
| group.leaves = group.leaves.sort((a, b) => { | ||
| const leafA = leavesById[a]; | ||
| const leafB = leavesById[b]; | ||
| return comparator(leafA, leafB); | ||
| }); | ||
| } | ||
| return group; | ||
| }; | ||
| sortGroupLeaves(root); | ||
| return tree; | ||
| return processTree(tree, { sort: comparator }); | ||
| }; | ||
| export const transformTree = (tree, transformer) => { | ||
| const visitedGroups = new Set(); | ||
| const { root, leavesById, groupsById } = tree; | ||
| const transformGroupLeaves = (group) => { | ||
| if (!transformer) { | ||
| return group; | ||
| } | ||
| if (group.groups?.length) { | ||
| group.groups.forEach((groupId) => { | ||
| if (visitedGroups.has(groupId)) { | ||
| return; | ||
| } | ||
| transformGroupLeaves(groupsById[groupId]); | ||
| visitedGroups.add(groupId); | ||
| }); | ||
| } | ||
| if (group.leaves?.length) { | ||
| group.leaves.forEach((leaf, i) => { | ||
| leavesById[leaf] = transformer(leavesById[leaf], i); | ||
| }); | ||
| } | ||
| return group; | ||
| }; | ||
| transformGroupLeaves(root); | ||
| return tree; | ||
| return processTree(tree, { transform: transformer }); | ||
| }; | ||
@@ -243,10 +257,3 @@ export const createTreeByTitlePath = (data, leafFactory, groupFactory, addLeafToGroup = () => { }) => { | ||
| const byLabelsAndTitlePath = (item, labelNames) => { | ||
| const leaves = []; | ||
| for (const labelName of labelNames) { | ||
| const values = item.labels.filter((label) => label.name === labelName).map((label) => label.value ?? ""); | ||
| if (!values.length) { | ||
| continue; | ||
| } | ||
| leaves.push(values); | ||
| } | ||
| const leaves = byLabelsWithFallback(item, labelNames, ""); | ||
| const titlePath = item.titlePath; | ||
@@ -253,0 +260,0 @@ if (Array.isArray(titlePath) && titlePath.length > 0) { |
+3
-2
| { | ||
| "name": "@allurereport/plugin-api", | ||
| "version": "3.8.2", | ||
| "version": "3.9.0", | ||
| "description": "Allure Plugin API", | ||
@@ -29,3 +29,3 @@ "keywords": [ | ||
| "dependencies": { | ||
| "@allurereport/core-api": "3.8.2" | ||
| "@allurereport/core-api": "3.9.0" | ||
| }, | ||
@@ -36,2 +36,3 @@ "devDependencies": { | ||
| "@vitest/snapshot": "^2.1.9", | ||
| "allure-js-commons": "^3.3.3", | ||
| "allure-vitest": "^3.3.3", | ||
@@ -38,0 +39,0 @@ "rimraf": "^6.0.1", |
32051
4.83%689
5.84%8
14.29%+ Added
- Removed
Updated