@allurereport/web-commons 3.0.0-beta.8 → 3.0.0
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/dist/attachments.d.ts +21 -0
- package/dist/attachments.js +162 -0
- package/dist/charts/accessors/coverageDiffTreeMapAccessor.d.ts +16 -0
- package/dist/charts/accessors/coverageDiffTreeMapAccessor.js +183 -0
- package/dist/charts/accessors/problemsDistributionHeatMap.d.ts +2 -0
- package/dist/charts/accessors/problemsDistributionHeatMap.js +65 -0
- package/dist/charts/accessors/severityTrendAccessor.d.ts +3 -0
- package/dist/charts/accessors/severityTrendAccessor.js +21 -0
- package/dist/charts/accessors/statusTrendAccessor.d.ts +3 -0
- package/dist/charts/accessors/statusTrendAccessor.js +19 -0
- package/dist/charts/accessors/successRateDistributionTreeMapAccessor.d.ts +14 -0
- package/dist/charts/accessors/successRateDistributionTreeMapAccessor.js +110 -0
- package/dist/charts/accessors/utils/behavior.d.ts +5 -0
- package/dist/charts/accessors/utils/behavior.js +4 -0
- package/dist/charts/chart-utils.d.ts +8 -0
- package/dist/charts/chart-utils.js +22 -0
- package/dist/charts/colors.d.ts +3 -0
- package/dist/charts/colors.js +18 -0
- package/dist/charts/d3pie.d.ts +3 -0
- package/dist/charts/d3pie.js +52 -0
- package/dist/charts/generateCurrentStatusChart.d.ts +3 -0
- package/dist/charts/generateCurrentStatusChart.js +10 -0
- package/dist/charts/generateDurationDynamicsChart.d.ts +5 -0
- package/dist/charts/generateDurationDynamicsChart.js +83 -0
- package/dist/charts/generateDurationsChart.d.ts +5 -0
- package/dist/charts/generateDurationsChart.js +81 -0
- package/dist/charts/generateFBSUAgePyramid.d.ts +5 -0
- package/dist/charts/generateFBSUAgePyramid.js +77 -0
- package/dist/charts/generateStabilityDistributionChart.d.ts +5 -0
- package/dist/charts/generateStabilityDistributionChart.js +64 -0
- package/dist/charts/generateStatusDynamicsChart.d.ts +6 -0
- package/dist/charts/generateStatusDynamicsChart.js +44 -0
- package/dist/charts/generateStatusTransitionsChart.d.ts +5 -0
- package/dist/charts/generateStatusTransitionsChart.js +91 -0
- package/dist/charts/generateTestBaseGrowthDynamicsChart.d.ts +5 -0
- package/dist/charts/generateTestBaseGrowthDynamicsChart.js +79 -0
- package/dist/charts/generateTestingPyramidChart.d.ts +2 -0
- package/dist/charts/generateTestingPyramidChart.js +52 -0
- package/dist/charts/generateTrSeveritiesChart.d.ts +5 -0
- package/dist/charts/generateTrSeveritiesChart.js +53 -0
- package/dist/charts/generators.d.ts +10 -0
- package/dist/charts/generators.js +97 -0
- package/dist/charts/heatMap.d.ts +3 -0
- package/dist/charts/heatMap.js +9 -0
- package/dist/charts/index.d.ts +9 -0
- package/dist/charts/index.js +8 -0
- package/dist/charts/line.d.ts +8 -0
- package/dist/charts/line.js +140 -0
- package/dist/charts/treeMap.d.ts +6 -0
- package/dist/charts/treeMap.js +87 -0
- package/dist/charts/types.d.ts +76 -0
- package/dist/charts/types.js +1 -0
- package/dist/charts/utils.d.ts +21 -0
- package/dist/charts/utils.js +188 -0
- package/dist/data.d.ts +7 -7
- package/dist/data.js +9 -35
- package/dist/i18n.d.ts +8 -0
- package/dist/i18n.js +119 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/sanitize.d.ts +1 -0
- package/dist/sanitize.js +2 -0
- package/dist/strings.d.ts +12 -0
- package/dist/strings.js +7 -0
- package/package.json +17 -6
- package/dist/static.d.ts +0 -8
- package/dist/static.js +0 -25
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ChartType } from "@allurereport/charts-api";
|
|
2
|
+
const DEFAULT_LAYERS = ["unit", "integration", "e2e"];
|
|
3
|
+
const getPercentage = (value, total) => {
|
|
4
|
+
if (total === 0 || value === 0) {
|
|
5
|
+
return 0;
|
|
6
|
+
}
|
|
7
|
+
return Math.floor((value / total) * 10000) / 100;
|
|
8
|
+
};
|
|
9
|
+
export const generateTestingPyramidChart = (chartOptions, storeData) => {
|
|
10
|
+
const { layers = DEFAULT_LAYERS, title } = chartOptions;
|
|
11
|
+
const { testResults } = storeData;
|
|
12
|
+
const layersMap = new Map();
|
|
13
|
+
layers.forEach((layer) => {
|
|
14
|
+
layersMap.set(layer, layer);
|
|
15
|
+
layersMap.set(layer.toLocaleLowerCase(), layer);
|
|
16
|
+
});
|
|
17
|
+
const statsByLayers = new Map();
|
|
18
|
+
layers.forEach((layer) => {
|
|
19
|
+
statsByLayers.set(layer, {
|
|
20
|
+
passed: 0,
|
|
21
|
+
total: 0,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
for (const testResult of testResults) {
|
|
25
|
+
const trLayer = testResult.labels.find((label) => label.name === "layer")?.value;
|
|
26
|
+
if (!trLayer) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const layer = layersMap.get(trLayer.toLocaleLowerCase());
|
|
30
|
+
if (!layer) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const data = statsByLayers.get(layer);
|
|
34
|
+
data.total++;
|
|
35
|
+
if (testResult.status === "passed") {
|
|
36
|
+
data.passed++;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
type: ChartType.TestingPyramid,
|
|
41
|
+
title,
|
|
42
|
+
data: layers.map((layer) => {
|
|
43
|
+
const data = statsByLayers.get(layer);
|
|
44
|
+
return {
|
|
45
|
+
layer,
|
|
46
|
+
testCount: data.total,
|
|
47
|
+
successRate: getPercentage(data.passed, data.total),
|
|
48
|
+
percentage: getPercentage(data.total, testResults.length),
|
|
49
|
+
};
|
|
50
|
+
}),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AllureChartsStoreData, TrSeveritiesChartData, TrSeveritiesChartOptions } from "@allurereport/charts-api";
|
|
2
|
+
export declare const generateTrSeveritiesChart: (props: {
|
|
3
|
+
options: TrSeveritiesChartOptions;
|
|
4
|
+
storeData: AllureChartsStoreData;
|
|
5
|
+
}) => TrSeveritiesChartData;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ChartType } from "@allurereport/charts-api";
|
|
2
|
+
import { severityLabelName, severityLevels, statusesList } from "@allurereport/core-api";
|
|
3
|
+
const DEFAULT_SEVERITY_LEVELS = [...severityLevels];
|
|
4
|
+
const UNSET_SEVERITY_LEVEL = "unset";
|
|
5
|
+
const SEVERITY_LABEL_NAME = severityLabelName;
|
|
6
|
+
const getSeverity = (tr) => {
|
|
7
|
+
const severityLabelValue = tr.labels?.find((label) => label.name === SEVERITY_LABEL_NAME)?.value;
|
|
8
|
+
if (!severityLabelValue) {
|
|
9
|
+
return UNSET_SEVERITY_LEVEL;
|
|
10
|
+
}
|
|
11
|
+
return severityLabelValue;
|
|
12
|
+
};
|
|
13
|
+
export const generateTrSeveritiesChart = (props) => {
|
|
14
|
+
const { options, storeData } = props;
|
|
15
|
+
const { levels, statuses, includeUnset = true } = options;
|
|
16
|
+
let trSeverityLevels = levels;
|
|
17
|
+
let trStatuses = statuses;
|
|
18
|
+
if (!trSeverityLevels || trSeverityLevels.length === 0) {
|
|
19
|
+
trSeverityLevels = DEFAULT_SEVERITY_LEVELS;
|
|
20
|
+
}
|
|
21
|
+
if (includeUnset) {
|
|
22
|
+
trSeverityLevels.push(UNSET_SEVERITY_LEVEL);
|
|
23
|
+
}
|
|
24
|
+
if (!trStatuses || trStatuses.length === 0) {
|
|
25
|
+
trStatuses = statusesList;
|
|
26
|
+
}
|
|
27
|
+
const { testResults } = storeData;
|
|
28
|
+
const data = new Map();
|
|
29
|
+
for (const severity of trSeverityLevels) {
|
|
30
|
+
data.set(severity, Object.fromEntries(trStatuses.map((status) => [status, 0])));
|
|
31
|
+
}
|
|
32
|
+
for (const tr of testResults) {
|
|
33
|
+
if (!trStatuses.includes(tr.status)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const severity = getSeverity(tr);
|
|
37
|
+
if (!trSeverityLevels.includes(severity)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const severityStats = data.get(severity);
|
|
41
|
+
severityStats[tr.status]++;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
type: ChartType.TrSeverities,
|
|
45
|
+
title: options.title,
|
|
46
|
+
data: trSeverityLevels.map((severity) => ({
|
|
47
|
+
id: severity,
|
|
48
|
+
...data.get(severity),
|
|
49
|
+
})),
|
|
50
|
+
levels: trSeverityLevels,
|
|
51
|
+
statuses: trStatuses,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ChartOptions, type GeneratedChartsData } from "@allurereport/charts-api";
|
|
2
|
+
import { type AllureStore } from "@allurereport/plugin-api";
|
|
3
|
+
type ChartsWidgetData = {
|
|
4
|
+
general: GeneratedChartsData;
|
|
5
|
+
byEnv: {
|
|
6
|
+
[env: string]: GeneratedChartsData;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export declare const generateCharts: (chartsOptions: ChartOptions[], store: AllureStore, reportName: string, generateUuid: () => string) => Promise<ChartsWidgetData>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ChartType, } from "@allurereport/charts-api";
|
|
2
|
+
import { DEFAULT_ENVIRONMENT } from "@allurereport/core-api";
|
|
3
|
+
import { generateCurrentStatusChart } from "./generateCurrentStatusChart.js";
|
|
4
|
+
import { generateDurationDynamicsChart } from "./generateDurationDynamicsChart.js";
|
|
5
|
+
import { generateDurationsChart } from "./generateDurationsChart.js";
|
|
6
|
+
import { generateFBSUAgePyramid } from "./generateFBSUAgePyramid.js";
|
|
7
|
+
import { generateStabilityDistributionChart } from "./generateStabilityDistributionChart.js";
|
|
8
|
+
import { generateStatusDynamicsChart } from "./generateStatusDynamicsChart.js";
|
|
9
|
+
import { generateStatusTransitionsChart } from "./generateStatusTransitionsChart.js";
|
|
10
|
+
import { generateTestBaseGrowthDynamicsChart } from "./generateTestBaseGrowthDynamicsChart.js";
|
|
11
|
+
import { generateTestingPyramidChart } from "./generateTestingPyramidChart.js";
|
|
12
|
+
import { generateTrSeveritiesChart } from "./generateTrSeveritiesChart.js";
|
|
13
|
+
import { generateHeatMapChart } from "./heatMap.js";
|
|
14
|
+
import { generateTreeMapChart } from "./treeMap.js";
|
|
15
|
+
const generateChartData = async (props) => {
|
|
16
|
+
const { env, chartsOptions, store, reportName, generateUuid } = props;
|
|
17
|
+
const result = {};
|
|
18
|
+
const storeData = await Promise.all([
|
|
19
|
+
env ? await store.allHistoryDataPointsByEnvironment(env) : await store.allHistoryDataPoints(),
|
|
20
|
+
env ? await store.testResultsByEnvironment(env) : await store.allTestResults(),
|
|
21
|
+
env ? await store.testsStatistic((tr) => tr.environment === env) : await store.testsStatistic(),
|
|
22
|
+
]).then(([historyDataPoints, testResults, statistic]) => ({
|
|
23
|
+
historyDataPoints,
|
|
24
|
+
testResults,
|
|
25
|
+
statistic,
|
|
26
|
+
}));
|
|
27
|
+
for (const chartOption of chartsOptions) {
|
|
28
|
+
const chartId = generateUuid();
|
|
29
|
+
switch (chartOption.type) {
|
|
30
|
+
case ChartType.CurrentStatus:
|
|
31
|
+
result[chartId] = generateCurrentStatusChart(chartOption, storeData);
|
|
32
|
+
break;
|
|
33
|
+
case ChartType.StatusDynamics:
|
|
34
|
+
result[chartId] = generateStatusDynamicsChart({ options: chartOption, storeData });
|
|
35
|
+
break;
|
|
36
|
+
case ChartType.StatusTransitions:
|
|
37
|
+
result[chartId] = generateStatusTransitionsChart({ options: chartOption, storeData });
|
|
38
|
+
break;
|
|
39
|
+
case ChartType.Durations:
|
|
40
|
+
result[chartId] = generateDurationsChart({ options: chartOption, storeData });
|
|
41
|
+
break;
|
|
42
|
+
case ChartType.DurationDynamics:
|
|
43
|
+
result[chartId] = generateDurationDynamicsChart({ options: chartOption, storeData });
|
|
44
|
+
break;
|
|
45
|
+
case ChartType.StabilityDistribution:
|
|
46
|
+
result[chartId] = generateStabilityDistributionChart({ options: chartOption, storeData });
|
|
47
|
+
break;
|
|
48
|
+
case ChartType.TestBaseGrowthDynamics:
|
|
49
|
+
result[chartId] = generateTestBaseGrowthDynamicsChart({ options: chartOption, storeData });
|
|
50
|
+
break;
|
|
51
|
+
case ChartType.FBSUAgePyramid:
|
|
52
|
+
result[chartId] = generateFBSUAgePyramid({ options: chartOption, storeData });
|
|
53
|
+
break;
|
|
54
|
+
case ChartType.TrSeverities:
|
|
55
|
+
result[chartId] = generateTrSeveritiesChart({ options: chartOption, storeData });
|
|
56
|
+
break;
|
|
57
|
+
case ChartType.CoverageDiff:
|
|
58
|
+
result[chartId] = generateTreeMapChart(chartOption, storeData);
|
|
59
|
+
break;
|
|
60
|
+
case ChartType.SuccessRateDistribution:
|
|
61
|
+
result[chartId] = generateTreeMapChart(chartOption, storeData);
|
|
62
|
+
break;
|
|
63
|
+
case ChartType.ProblemsDistribution:
|
|
64
|
+
result[chartId] = generateHeatMapChart(chartOption, storeData);
|
|
65
|
+
break;
|
|
66
|
+
case ChartType.TestingPyramid:
|
|
67
|
+
result[chartId] = generateTestingPyramidChart(chartOption, storeData);
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
};
|
|
75
|
+
const hasOnlyDefaultEnvironment = (environments) => {
|
|
76
|
+
return environments.length === 1 && environments[0] === DEFAULT_ENVIRONMENT;
|
|
77
|
+
};
|
|
78
|
+
export const generateCharts = async (chartsOptions, store, reportName, generateUuid) => {
|
|
79
|
+
const environments = await store.allEnvironments();
|
|
80
|
+
const chartsData = {
|
|
81
|
+
general: await generateChartData({ chartsOptions, store, reportName, generateUuid }),
|
|
82
|
+
byEnv: {},
|
|
83
|
+
};
|
|
84
|
+
if (hasOnlyDefaultEnvironment(environments)) {
|
|
85
|
+
return chartsData;
|
|
86
|
+
}
|
|
87
|
+
for (const environment of environments) {
|
|
88
|
+
chartsData.byEnv[environment] = await generateChartData({
|
|
89
|
+
chartsOptions,
|
|
90
|
+
store,
|
|
91
|
+
reportName,
|
|
92
|
+
env: environment,
|
|
93
|
+
generateUuid,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return chartsData;
|
|
97
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AllureChartsStoreData, HeatMapChartData, HeatMapChartOptions, HeatMapDataAccessor } from "@allurereport/charts-api";
|
|
2
|
+
export declare const generateHeatMapChartGeneric: <T extends Record<string, unknown>>(options: HeatMapChartOptions, storeData: AllureChartsStoreData, dataAccessor: HeatMapDataAccessor<T>) => HeatMapChartData | undefined;
|
|
3
|
+
export declare const generateHeatMapChart: (options: HeatMapChartOptions, storeData: AllureChartsStoreData) => HeatMapChartData | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { problemsDistributionHeatMapAccessor } from "./accessors/problemsDistributionHeatMap.js";
|
|
2
|
+
export const generateHeatMapChartGeneric = (options, storeData, dataAccessor) => ({
|
|
3
|
+
type: options.type,
|
|
4
|
+
title: options.title,
|
|
5
|
+
data: dataAccessor.getHeatMap(storeData),
|
|
6
|
+
});
|
|
7
|
+
export const generateHeatMapChart = (options, storeData) => {
|
|
8
|
+
return generateHeatMapChartGeneric(options, storeData, problemsDistributionHeatMapAccessor);
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./utils.js";
|
|
2
|
+
export type * from "./types.js";
|
|
3
|
+
export * from "./colors.js";
|
|
4
|
+
export * from "./chart-utils.js";
|
|
5
|
+
export * from "./line.js";
|
|
6
|
+
export * from "./treeMap.js";
|
|
7
|
+
export * from "./heatMap.js";
|
|
8
|
+
export * from "./d3pie.js";
|
|
9
|
+
export * from "./generators.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AllureChartsStoreData, BaseTrendSliceMetadata, GenericTrendChartData, TrendCalculationResult, TrendChartData, TrendDataAccessor, TrendDataType } from "@allurereport/charts-api";
|
|
2
|
+
type TrendChartOptions = Record<string, any>;
|
|
3
|
+
export declare const calculatePercentValues: <T extends TrendDataType>(stats: Record<T, number>, executionId: string, itemType: readonly T[]) => TrendCalculationResult<T>;
|
|
4
|
+
export declare const getTrendDataGeneric: <T extends TrendDataType, M extends BaseTrendSliceMetadata>(stats: Record<T, number>, reportName: string, executionOrder: number, itemType: readonly T[], chartOptions: TrendChartOptions) => GenericTrendChartData<T, M>;
|
|
5
|
+
export declare const mergeTrendDataGeneric: <T extends TrendDataType, M extends BaseTrendSliceMetadata>(trendData: GenericTrendChartData<T, M>, trendDataPart: GenericTrendChartData<T, M>, itemType: readonly T[]) => GenericTrendChartData<T, M>;
|
|
6
|
+
export declare const generateTrendChartGeneric: <T extends TrendDataType>(options: TrendChartOptions, storeData: AllureChartsStoreData, dataAccessor: TrendDataAccessor<T>, reportName: string) => GenericTrendChartData<T> | undefined;
|
|
7
|
+
export declare const generateTrendChart: (options: TrendChartOptions, storeData: AllureChartsStoreData, reportName: string) => TrendChartData | undefined;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ChartDataType, ChartMode, DEFAULT_CHART_HISTORY_LIMIT } from "@allurereport/charts-api";
|
|
2
|
+
import { severityTrendDataAccessor } from "./accessors/severityTrendAccessor.js";
|
|
3
|
+
import { statusTrendDataAccessor } from "./accessors/statusTrendAccessor.js";
|
|
4
|
+
import { createEmptySeries, normalizeStatistic } from "./chart-utils.js";
|
|
5
|
+
export const calculatePercentValues = (stats, executionId, itemType) => {
|
|
6
|
+
const points = {};
|
|
7
|
+
const series = createEmptySeries(itemType);
|
|
8
|
+
const values = Object.values(stats);
|
|
9
|
+
const total = values.reduce((sum, value) => sum + value, 0);
|
|
10
|
+
if (total === 0) {
|
|
11
|
+
return { points, series };
|
|
12
|
+
}
|
|
13
|
+
itemType.forEach((item) => {
|
|
14
|
+
const pointId = `${executionId}-${item}`;
|
|
15
|
+
const value = stats[item] ?? 0;
|
|
16
|
+
points[pointId] = {
|
|
17
|
+
x: executionId,
|
|
18
|
+
y: value / total,
|
|
19
|
+
};
|
|
20
|
+
series[item].push(pointId);
|
|
21
|
+
});
|
|
22
|
+
return { points, series };
|
|
23
|
+
};
|
|
24
|
+
const calculateRawValues = (stats, executionId, itemType) => {
|
|
25
|
+
const points = {};
|
|
26
|
+
const series = createEmptySeries(itemType);
|
|
27
|
+
itemType.forEach((item) => {
|
|
28
|
+
const pointId = `${executionId}-${item}`;
|
|
29
|
+
const value = stats[item] ?? 0;
|
|
30
|
+
points[pointId] = {
|
|
31
|
+
x: executionId,
|
|
32
|
+
y: value,
|
|
33
|
+
};
|
|
34
|
+
series[item].push(pointId);
|
|
35
|
+
});
|
|
36
|
+
return { points, series };
|
|
37
|
+
};
|
|
38
|
+
export const getTrendDataGeneric = (stats, reportName, executionOrder, itemType, chartOptions) => {
|
|
39
|
+
const { type, dataType, title, mode = ChartMode.Raw, metadata = {} } = chartOptions;
|
|
40
|
+
const { executionIdAccessor, executionNameAccessor } = metadata;
|
|
41
|
+
const executionId = executionIdAccessor ? executionIdAccessor(executionOrder) : `execution-${executionOrder}`;
|
|
42
|
+
const { points, series } = mode === ChartMode.Percent
|
|
43
|
+
? calculatePercentValues(stats, executionId, itemType)
|
|
44
|
+
: calculateRawValues(stats, executionId, itemType);
|
|
45
|
+
const slices = {};
|
|
46
|
+
const pointsAsArray = Object.values(points);
|
|
47
|
+
const pointsCount = pointsAsArray.length;
|
|
48
|
+
const values = pointsAsArray.map((point) => point.y);
|
|
49
|
+
const min = pointsCount ? Math.min(...values) : 0;
|
|
50
|
+
const max = pointsCount ? Math.max(...values) : 0;
|
|
51
|
+
if (pointsCount > 0) {
|
|
52
|
+
const executionName = executionNameAccessor ? executionNameAccessor(executionOrder) : reportName;
|
|
53
|
+
slices[executionId] = {
|
|
54
|
+
min,
|
|
55
|
+
max,
|
|
56
|
+
metadata: {
|
|
57
|
+
executionId,
|
|
58
|
+
executionName,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
type,
|
|
64
|
+
dataType,
|
|
65
|
+
mode,
|
|
66
|
+
title,
|
|
67
|
+
points,
|
|
68
|
+
slices,
|
|
69
|
+
series,
|
|
70
|
+
min,
|
|
71
|
+
max,
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
export const mergeTrendDataGeneric = (trendData, trendDataPart, itemType) => {
|
|
75
|
+
return {
|
|
76
|
+
...trendData,
|
|
77
|
+
points: {
|
|
78
|
+
...trendData.points,
|
|
79
|
+
...trendDataPart.points,
|
|
80
|
+
},
|
|
81
|
+
slices: {
|
|
82
|
+
...trendData.slices,
|
|
83
|
+
...trendDataPart.slices,
|
|
84
|
+
},
|
|
85
|
+
series: Object.entries(trendDataPart.series).reduce((series, [group, pointIds]) => {
|
|
86
|
+
if (Array.isArray(pointIds)) {
|
|
87
|
+
return {
|
|
88
|
+
...series,
|
|
89
|
+
[group]: [...(trendData.series?.[group] || []), ...pointIds],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return series;
|
|
93
|
+
}, trendData.series || createEmptySeries(itemType)),
|
|
94
|
+
min: Math.min(trendData.min ?? Infinity, trendDataPart.min),
|
|
95
|
+
max: Math.max(trendData.max ?? -Infinity, trendDataPart.max),
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
export const generateTrendChartGeneric = (options, storeData, dataAccessor, reportName) => {
|
|
99
|
+
const { limit } = options;
|
|
100
|
+
const historyLimit = limit && limit > 0 ? Math.max(0, limit - 1) : undefined;
|
|
101
|
+
const { historyDataPoints } = storeData;
|
|
102
|
+
const currentData = dataAccessor.getCurrentData(storeData);
|
|
103
|
+
const limitedHistoryPoints = historyLimit !== undefined ? historyDataPoints.slice(-historyLimit) : historyDataPoints;
|
|
104
|
+
const firstOriginalIndex = historyLimit !== undefined ? Math.max(0, historyDataPoints.length - historyLimit) : 0;
|
|
105
|
+
const convertedHistoryPoints = limitedHistoryPoints.map((point, index) => {
|
|
106
|
+
const originalIndex = firstOriginalIndex + index;
|
|
107
|
+
return {
|
|
108
|
+
name: point.name,
|
|
109
|
+
originalIndex,
|
|
110
|
+
statistic: dataAccessor.getHistoricalData(point),
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
const allValues = dataAccessor.getAllValues();
|
|
114
|
+
const currentTrendData = getTrendDataGeneric(normalizeStatistic(currentData, allValues), reportName, historyDataPoints.length + 1, allValues, options);
|
|
115
|
+
const historicalTrendData = convertedHistoryPoints.reduce((acc, historyPoint) => {
|
|
116
|
+
const trendDataPart = getTrendDataGeneric(normalizeStatistic(historyPoint.statistic, allValues), historyPoint.name, historyPoint.originalIndex + 1, allValues, options);
|
|
117
|
+
return mergeTrendDataGeneric(acc, trendDataPart, allValues);
|
|
118
|
+
}, {
|
|
119
|
+
type: options.type,
|
|
120
|
+
dataType: options.dataType,
|
|
121
|
+
mode: options.mode,
|
|
122
|
+
title: options.title,
|
|
123
|
+
points: {},
|
|
124
|
+
slices: {},
|
|
125
|
+
series: createEmptySeries(allValues),
|
|
126
|
+
min: Infinity,
|
|
127
|
+
max: -Infinity,
|
|
128
|
+
});
|
|
129
|
+
return mergeTrendDataGeneric(historicalTrendData, currentTrendData, allValues);
|
|
130
|
+
};
|
|
131
|
+
export const generateTrendChart = (options, storeData, reportName) => {
|
|
132
|
+
const newOptions = { limit: DEFAULT_CHART_HISTORY_LIMIT, ...options };
|
|
133
|
+
const { dataType } = newOptions;
|
|
134
|
+
if (dataType === ChartDataType.Status) {
|
|
135
|
+
return generateTrendChartGeneric(newOptions, storeData, statusTrendDataAccessor, reportName);
|
|
136
|
+
}
|
|
137
|
+
else if (dataType === ChartDataType.Severity) {
|
|
138
|
+
return generateTrendChartGeneric(newOptions, storeData, severityTrendDataAccessor, reportName);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AllureChartsStoreData, TreeMapChartData, TreeMapChartOptions, TreeMapDataAccessor, TreeMapNode } from "@allurereport/charts-api";
|
|
2
|
+
import type { TreeData, TreeGroup, TreeLeaf, WithChildren } from "@allurereport/core-api";
|
|
3
|
+
export declare const convertTreeDataToTreeMapNode: <T extends TreeMapNode, L, G>(treeData: TreeData<L, G>, transform: (treeDataNode: TreeLeaf<L> | TreeGroup<G>, isGroup: boolean, parentNode?: TreeGroup<G>) => T, transformRoot?: (root: WithChildren) => T) => T;
|
|
4
|
+
export declare const transformTreeMapNode: <T extends TreeMapNode>(tree: T, transform: (node: T) => T) => T;
|
|
5
|
+
export declare const generateTreeMapChartGeneric: <T extends TreeMapNode>(options: TreeMapChartOptions, storeData: AllureChartsStoreData, dataAccessor: TreeMapDataAccessor<T>) => TreeMapChartData | undefined;
|
|
6
|
+
export declare const generateTreeMapChart: (options: TreeMapChartOptions, storeData: AllureChartsStoreData) => TreeMapChartData | undefined;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ChartType } from "@allurereport/charts-api";
|
|
2
|
+
import { coverageDiffTreeMapAccessor } from "./accessors/coverageDiffTreeMapAccessor.js";
|
|
3
|
+
import { successRateDistributionTreeMapAccessor } from "./accessors/successRateDistributionTreeMapAccessor.js";
|
|
4
|
+
export const convertTreeDataToTreeMapNode = (treeData, transform, transformRoot = () => ({
|
|
5
|
+
id: "root",
|
|
6
|
+
value: undefined,
|
|
7
|
+
})) => {
|
|
8
|
+
const { root, leavesById, groupsById } = treeData;
|
|
9
|
+
const convertNode = (nodeId, parentGroup, isGroup) => {
|
|
10
|
+
const node = isGroup ? groupsById[nodeId] : leavesById[nodeId];
|
|
11
|
+
if (!node) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const treeMapNode = transform(node, isGroup, parentGroup);
|
|
15
|
+
if (isGroup) {
|
|
16
|
+
const group = node;
|
|
17
|
+
const children = [];
|
|
18
|
+
if (group.groups) {
|
|
19
|
+
group.groups.forEach((groupId) => {
|
|
20
|
+
const childNode = convertNode(groupId, group, true);
|
|
21
|
+
if (childNode) {
|
|
22
|
+
children.push(childNode);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (group.leaves) {
|
|
27
|
+
group.leaves.forEach((leafId) => {
|
|
28
|
+
const childNode = convertNode(leafId, group, false);
|
|
29
|
+
if (childNode) {
|
|
30
|
+
children.push(childNode);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (children.length === 0) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
treeMapNode.children = children;
|
|
38
|
+
}
|
|
39
|
+
return treeMapNode;
|
|
40
|
+
};
|
|
41
|
+
const rootChildren = [];
|
|
42
|
+
if (root.groups) {
|
|
43
|
+
root.groups.forEach((groupId) => {
|
|
44
|
+
const childNode = convertNode(groupId, root, true);
|
|
45
|
+
if (childNode) {
|
|
46
|
+
rootChildren.push(childNode);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (root.leaves) {
|
|
51
|
+
root.leaves.forEach((leafId) => {
|
|
52
|
+
const childNode = convertNode(leafId, root, false);
|
|
53
|
+
if (childNode) {
|
|
54
|
+
rootChildren.push(childNode);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
children: rootChildren.length > 0 ? rootChildren : undefined,
|
|
60
|
+
...transformRoot(root),
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
export const transformTreeMapNode = (tree, transform) => {
|
|
64
|
+
const transformedNode = transform(tree);
|
|
65
|
+
if (transformedNode.children) {
|
|
66
|
+
const transformedChildren = transformedNode.children.map((child) => transformTreeMapNode(child, transform));
|
|
67
|
+
return {
|
|
68
|
+
...transformedNode,
|
|
69
|
+
children: transformedChildren,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return transformedNode;
|
|
73
|
+
};
|
|
74
|
+
export const generateTreeMapChartGeneric = (options, storeData, dataAccessor) => ({
|
|
75
|
+
type: options.type,
|
|
76
|
+
title: options.title,
|
|
77
|
+
treeMap: dataAccessor.getTreeMap(storeData),
|
|
78
|
+
});
|
|
79
|
+
export const generateTreeMapChart = (options, storeData) => {
|
|
80
|
+
const { type } = options;
|
|
81
|
+
if (type === ChartType.SuccessRateDistribution) {
|
|
82
|
+
return generateTreeMapChartGeneric(options, storeData, successRateDistributionTreeMapAccessor);
|
|
83
|
+
}
|
|
84
|
+
else if (type === ChartType.CoverageDiff) {
|
|
85
|
+
return generateTreeMapChartGeneric(options, storeData, coverageDiffTreeMapAccessor);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { ChartId, ChartType, DurationDynamicsChartData, DurationsChartData, FBSUAgePyramidChartData, HeatMapSerie, StabilityDistributionChartData, StatusTransitionsChartData, TestBaseGrowthDynamicsChartData, TestingPyramidChartData, TrSeveritiesChartData, TreeMapNode } from "@allurereport/charts-api";
|
|
2
|
+
import type { Statistic, TestStatus } from "@allurereport/core-api";
|
|
3
|
+
export type TreeMapTooltipAccessor = <T>(node: T) => string[];
|
|
4
|
+
export interface Point {
|
|
5
|
+
x: Date | string | number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TrendChartItem {
|
|
9
|
+
id: string;
|
|
10
|
+
data: Point[];
|
|
11
|
+
color: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CurrentStatusChartData {
|
|
14
|
+
type: ChartType.CurrentStatus;
|
|
15
|
+
title?: string;
|
|
16
|
+
data: Statistic;
|
|
17
|
+
statuses?: TestStatus[];
|
|
18
|
+
metric?: TestStatus;
|
|
19
|
+
}
|
|
20
|
+
export interface StatusDynamicsChartData {
|
|
21
|
+
type: ChartType.StatusDynamics;
|
|
22
|
+
title?: string;
|
|
23
|
+
data: {
|
|
24
|
+
statistic: Statistic;
|
|
25
|
+
id: string;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
name: string;
|
|
28
|
+
}[];
|
|
29
|
+
limit?: number;
|
|
30
|
+
statuses?: TestStatus[];
|
|
31
|
+
}
|
|
32
|
+
export interface ResponseTreeMapChartData {
|
|
33
|
+
type: ChartType.CoverageDiff | ChartType.SuccessRateDistribution;
|
|
34
|
+
title?: string;
|
|
35
|
+
treeMap: TreeMapNode;
|
|
36
|
+
}
|
|
37
|
+
export interface ResponseHeatMapChartData {
|
|
38
|
+
type: ChartType.ProblemsDistribution;
|
|
39
|
+
title?: string;
|
|
40
|
+
data: HeatMapSerie[];
|
|
41
|
+
}
|
|
42
|
+
export type ChartsResponse = {
|
|
43
|
+
general: Record<ChartId, CurrentStatusChartData | ResponseTreeMapChartData | ResponseHeatMapChartData>;
|
|
44
|
+
byEnv: {
|
|
45
|
+
[env: string]: Record<ChartId, CurrentStatusChartData | ResponseTreeMapChartData | ResponseHeatMapChartData>;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export type UICurrentStatusChartData = CurrentStatusChartData;
|
|
49
|
+
export type UIStatusDynamicsChartData = StatusDynamicsChartData;
|
|
50
|
+
export type UIStatusTransitionsChartData = StatusTransitionsChartData;
|
|
51
|
+
export type UIDurationsChartData = DurationsChartData;
|
|
52
|
+
export interface UITreeMapChartData extends ResponseTreeMapChartData {
|
|
53
|
+
colors: (value: number, domain?: number[]) => string;
|
|
54
|
+
formatLegend?: (value: number) => string;
|
|
55
|
+
legendDomain?: number[];
|
|
56
|
+
tooltipRows?: TreeMapTooltipAccessor;
|
|
57
|
+
}
|
|
58
|
+
export interface UIHeatMapChartData extends ResponseHeatMapChartData {
|
|
59
|
+
colors: (value: number, domain?: number[]) => string;
|
|
60
|
+
}
|
|
61
|
+
export type ChartData = CurrentStatusChartData | StatusDynamicsChartData | StatusTransitionsChartData | DurationsChartData | StabilityDistributionChartData | ResponseTreeMapChartData | ResponseHeatMapChartData | TestBaseGrowthDynamicsChartData | FBSUAgePyramidChartData | TrSeveritiesChartData | DurationDynamicsChartData | TestingPyramidChartData;
|
|
62
|
+
export type UIChartData = UICurrentStatusChartData | UIStatusDynamicsChartData | UITreeMapChartData | UIHeatMapChartData | UIStatusTransitionsChartData | UIDurationsChartData | TestBaseGrowthDynamicsChartData | FBSUAgePyramidChartData | StabilityDistributionChartData | TrSeveritiesChartData | DurationDynamicsChartData | TestingPyramidChartData;
|
|
63
|
+
export type ChartsData = Record<ChartId, ChartData>;
|
|
64
|
+
export type ChartsDataWithEnvs = {
|
|
65
|
+
general: Record<ChartId, ChartData>;
|
|
66
|
+
byEnv: {
|
|
67
|
+
[env: string]: Record<ChartId, ChartData>;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export type UIChartsData = Record<ChartId, UIChartData>;
|
|
71
|
+
export type UIChartsDataWithEnvs = {
|
|
72
|
+
general: UIChartsData;
|
|
73
|
+
byEnv: {
|
|
74
|
+
[env: string]: UIChartsData;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ChartId } from "@allurereport/charts-api";
|
|
2
|
+
import type { ChartsData, ChartsDataWithEnvs, ResponseHeatMapChartData, ResponseTreeMapChartData, TreeMapTooltipAccessor, UIChartData, UIChartsDataWithEnvs, UIHeatMapChartData, UITreeMapChartData } from "./types.js";
|
|
3
|
+
export declare const createTreeMapChartDataGeneric: (getChart: () => ResponseTreeMapChartData | undefined, colors: (value: number, domain?: number[]) => string, formatLegend?: (value: number) => string, legendDomain?: number[], tooltipRows?: TreeMapTooltipAccessor) => UITreeMapChartData | undefined;
|
|
4
|
+
export declare const createHeatMapChartDataGeneric: (getChart: () => ResponseHeatMapChartData | undefined, colors: (value: number, domain?: number[]) => string) => UIHeatMapChartData | undefined;
|
|
5
|
+
export declare const createSuccessRateDistributionTreeMapChartData: (chartId: ChartId, res: ChartsData) => UITreeMapChartData | undefined;
|
|
6
|
+
export declare const createCoverageDiffTreeMapChartData: (chartId: ChartId, res: ChartsData) => UITreeMapChartData | undefined;
|
|
7
|
+
export declare const createProblemsDistributionHeatMapChartData: (chartId: ChartId, res: ChartsData) => UIHeatMapChartData | undefined;
|
|
8
|
+
export declare const createTreeMapChartData: (chartId: ChartId, chartData: ResponseTreeMapChartData, res: ChartsData) => UITreeMapChartData | undefined;
|
|
9
|
+
export declare const createHeatMapChartData: (chartId: ChartId, res: ChartsData) => UIHeatMapChartData | undefined;
|
|
10
|
+
export declare const createCharts: (res: ChartsData) => Record<ChartId, UIChartData>;
|
|
11
|
+
export declare const createChartsWithEnvs: (res: ChartsDataWithEnvs) => UIChartsDataWithEnvs;
|
|
12
|
+
export declare const createHashStorage: () => {
|
|
13
|
+
get: (key: string) => string;
|
|
14
|
+
set: (key: string, value: string) => Map<string, string>;
|
|
15
|
+
};
|
|
16
|
+
export declare const createMapWithDefault: <K, V>(defaultValue: V) => {
|
|
17
|
+
readonly set: (key: K, value: V) => Map<K, V>;
|
|
18
|
+
readonly get: (key: K) => NonNullable<V>;
|
|
19
|
+
readonly values: V[];
|
|
20
|
+
readonly entries: [K, V][];
|
|
21
|
+
};
|