mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard Schema v2: Add tests for variables, annotations, and dataTransformer (#97314)
* Add tests for variables, annotations, dataTransformer * Simplify variable validation; test additional variable fields * Move helpers to a separate file * remove unused param, rename helpers file * fix * Move remaining vizPanel test to helper * use ts
This commit is contained in:
parent
6bdd8f7fca
commit
9e885cab7c
@ -2279,6 +2279,9 @@ exports[`better eslint`] = {
|
||||
"public/app/features/dashboard-scene/utils/PanelModelCompatibilityWrapper.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/v2schema/test-helpers.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard/api/dashboard_api.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
|
@ -22,7 +22,91 @@ export const handyTestingSchema: DashboardV2Spec = {
|
||||
to: 'now',
|
||||
weekStart: 'monday',
|
||||
},
|
||||
annotations: [],
|
||||
annotations: [
|
||||
{
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
builtIn: true,
|
||||
query: {
|
||||
kind: 'prometheus',
|
||||
spec: {
|
||||
expr: 'test-query',
|
||||
},
|
||||
},
|
||||
datasource: {
|
||||
type: 'prometheus',
|
||||
uid: 'uid',
|
||||
},
|
||||
filter: { ids: [] },
|
||||
enable: true,
|
||||
hide: false,
|
||||
iconColor: 'rgba(0, 211, 255, 1)',
|
||||
name: 'Annotations & Alerts',
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
datasource: {
|
||||
type: 'grafana-testdata-datasource',
|
||||
uid: 'uid',
|
||||
},
|
||||
enable: true,
|
||||
iconColor: 'red',
|
||||
name: 'Enabled',
|
||||
query: {
|
||||
kind: 'grafana-testdata-datasource',
|
||||
spec: {
|
||||
lines: 4,
|
||||
refId: 'Anno',
|
||||
scenarioId: 'annotations',
|
||||
},
|
||||
},
|
||||
filter: { ids: [] },
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
datasource: {
|
||||
type: 'grafana-testdata-datasource',
|
||||
uid: 'uid',
|
||||
},
|
||||
filter: { ids: [] },
|
||||
enable: false,
|
||||
iconColor: 'yellow',
|
||||
name: 'Disabled',
|
||||
query: {
|
||||
kind: 'grafana-testdata-datasource',
|
||||
spec: { lines: 5, refId: 'Anno', scenarioId: 'annotations' },
|
||||
},
|
||||
hide: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'AnnotationQuery',
|
||||
spec: {
|
||||
datasource: {
|
||||
type: 'grafana-testdata-datasource',
|
||||
uid: 'uid',
|
||||
},
|
||||
filter: { ids: [] },
|
||||
enable: true,
|
||||
hide: true,
|
||||
iconColor: 'dark-purple',
|
||||
name: 'Hidden',
|
||||
query: {
|
||||
kind: 'grafana-testdata-datasource',
|
||||
spec: {
|
||||
lines: 6,
|
||||
refId: 'Anno',
|
||||
scenarioId: 'annotations',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
elements: {
|
||||
'test-panel-uid': {
|
||||
kind: 'Panel',
|
||||
|
@ -1,15 +1,38 @@
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { behaviors, sceneGraph, SceneQueryRunner } from '@grafana/scenes';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0/dashboard.gen';
|
||||
import {
|
||||
behaviors,
|
||||
ConstantVariable,
|
||||
CustomVariable,
|
||||
DataSourceVariable,
|
||||
IntervalVariable,
|
||||
QueryVariable,
|
||||
TextBoxVariable,
|
||||
sceneGraph,
|
||||
GroupByVariable,
|
||||
AdHocFiltersVariable,
|
||||
} from '@grafana/scenes';
|
||||
import {
|
||||
AdhocVariableKind,
|
||||
ConstantVariableKind,
|
||||
CustomVariableKind,
|
||||
DashboardV2Spec,
|
||||
DatasourceVariableKind,
|
||||
GroupByVariableKind,
|
||||
IntervalVariableKind,
|
||||
QueryVariableKind,
|
||||
TextVariableKind,
|
||||
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0/dashboard.gen';
|
||||
import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0/examples';
|
||||
import { DashboardWithAccessInfo } from 'app/features/dashboard/api/dashboard_api';
|
||||
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
||||
|
||||
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
|
||||
import { DashboardLayoutManager } from '../scene/types';
|
||||
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
||||
import { getQueryRunnerFor } from '../utils/utils';
|
||||
import { validateVariable, validateVizPanel } from '../v2schema/test-helpers';
|
||||
|
||||
import { transformSaveModelSchemaV2ToScene } from './transformSaveModelSchemaV2ToScene';
|
||||
import { transformCursorSynctoEnum } from './transformToV2TypesUtils';
|
||||
@ -85,14 +108,96 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
expect(dashboardControls.state.refreshPicker.state.intervals).toEqual(time.autoRefreshIntervals);
|
||||
expect(dashboardControls.state.hideTimeControls).toBe(time.hideTimepicker);
|
||||
|
||||
// TODO: Variables
|
||||
// expect(scene.state?.$variables?.state.variables).toHaveLength(dash.variables.length);
|
||||
// expect(scene.state?.$variables?.getByName(dash.variables[0].spec.name)).toBeInstanceOf(QueryVariable);
|
||||
// expect(scene.state?.$variables?.getByName(dash.variables[1].spec.name)).toBeInstanceOf(TextBoxVariable); ...
|
||||
// Variables
|
||||
const variables = scene.state?.$variables;
|
||||
expect(variables?.state.variables).toHaveLength(dash.variables.length);
|
||||
validateVariable({
|
||||
sceneVariable: variables?.state.variables[0],
|
||||
variableKind: dash.variables[0] as QueryVariableKind,
|
||||
scene: scene,
|
||||
dashSpec: dash,
|
||||
sceneVariableClass: QueryVariable,
|
||||
index: 0,
|
||||
});
|
||||
validateVariable({
|
||||
sceneVariable: variables?.state.variables[1],
|
||||
variableKind: dash.variables[1] as CustomVariableKind,
|
||||
scene: scene,
|
||||
dashSpec: dash,
|
||||
sceneVariableClass: CustomVariable,
|
||||
index: 1,
|
||||
});
|
||||
validateVariable({
|
||||
sceneVariable: variables?.state.variables[2],
|
||||
variableKind: dash.variables[2] as DatasourceVariableKind,
|
||||
scene: scene,
|
||||
dashSpec: dash,
|
||||
sceneVariableClass: DataSourceVariable,
|
||||
index: 2,
|
||||
});
|
||||
validateVariable({
|
||||
sceneVariable: variables?.state.variables[3],
|
||||
variableKind: dash.variables[3] as ConstantVariableKind,
|
||||
scene: scene,
|
||||
dashSpec: dash,
|
||||
sceneVariableClass: ConstantVariable,
|
||||
index: 3,
|
||||
});
|
||||
validateVariable({
|
||||
sceneVariable: variables?.state.variables[4],
|
||||
variableKind: dash.variables[4] as IntervalVariableKind,
|
||||
scene: scene,
|
||||
dashSpec: dash,
|
||||
sceneVariableClass: IntervalVariable,
|
||||
index: 4,
|
||||
});
|
||||
validateVariable({
|
||||
sceneVariable: variables?.state.variables[5],
|
||||
variableKind: dash.variables[5] as TextVariableKind,
|
||||
scene: scene,
|
||||
dashSpec: dash,
|
||||
sceneVariableClass: TextBoxVariable,
|
||||
index: 5,
|
||||
});
|
||||
validateVariable({
|
||||
sceneVariable: variables?.state.variables[6],
|
||||
variableKind: dash.variables[6] as GroupByVariableKind,
|
||||
scene: scene,
|
||||
dashSpec: dash,
|
||||
sceneVariableClass: GroupByVariable,
|
||||
index: 6,
|
||||
});
|
||||
validateVariable({
|
||||
sceneVariable: variables?.state.variables[7],
|
||||
variableKind: dash.variables[7] as AdhocVariableKind,
|
||||
scene: scene,
|
||||
dashSpec: dash,
|
||||
sceneVariableClass: AdHocFiltersVariable,
|
||||
index: 7,
|
||||
});
|
||||
|
||||
// TODO: Annotations
|
||||
// expect(scene.state.annotations).toHaveLength(dash.annotations.length);
|
||||
// expect(scene.state.annotations[0].text).toBe(dash.annotations[0].text); ...
|
||||
// Annotations
|
||||
expect(scene.state.$data).toBeInstanceOf(DashboardDataLayerSet);
|
||||
const dataLayers = scene.state.$data as DashboardDataLayerSet;
|
||||
expect(dataLayers.state.annotationLayers).toHaveLength(dash.annotations.length);
|
||||
expect(dataLayers.state.annotationLayers[0].state.name).toBe(dash.annotations[0].spec.name);
|
||||
expect(dataLayers.state.annotationLayers[0].state.isEnabled).toBe(dash.annotations[0].spec.enable);
|
||||
expect(dataLayers.state.annotationLayers[0].state.isHidden).toBe(dash.annotations[0].spec.hide);
|
||||
|
||||
// Enabled
|
||||
expect(dataLayers.state.annotationLayers[1].state.name).toBe(dash.annotations[1].spec.name);
|
||||
expect(dataLayers.state.annotationLayers[1].state.isEnabled).toBe(dash.annotations[1].spec.enable);
|
||||
expect(dataLayers.state.annotationLayers[1].state.isHidden).toBe(dash.annotations[1].spec.hide);
|
||||
|
||||
// Disabled
|
||||
expect(dataLayers.state.annotationLayers[2].state.name).toBe(dash.annotations[2].spec.name);
|
||||
expect(dataLayers.state.annotationLayers[2].state.isEnabled).toBe(dash.annotations[2].spec.enable);
|
||||
expect(dataLayers.state.annotationLayers[2].state.isHidden).toBe(dash.annotations[2].spec.hide);
|
||||
|
||||
// Hidden
|
||||
expect(dataLayers.state.annotationLayers[3].state.name).toBe(dash.annotations[3].spec.name);
|
||||
expect(dataLayers.state.annotationLayers[3].state.isEnabled).toBe(dash.annotations[3].spec.enable);
|
||||
expect(dataLayers.state.annotationLayers[3].state.isHidden).toBe(dash.annotations[3].spec.hide);
|
||||
|
||||
// To be implemented
|
||||
// expect(timePicker.state.ranges).toEqual(dash.timeSettings.quickRanges);
|
||||
@ -101,31 +206,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
|
||||
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
|
||||
expect(vizPanels).toHaveLength(1);
|
||||
const vizPanel = vizPanels[0];
|
||||
expect(vizPanel.state.title).toBe(dash.elements['test-panel-uid'].spec.title);
|
||||
expect(vizPanel.state.description).toBe(dash.elements['test-panel-uid'].spec.description);
|
||||
expect(vizPanel.state.pluginId).toBe(dash.elements['test-panel-uid'].spec.vizConfig.kind);
|
||||
expect(vizPanel.state.pluginVersion).toBe(dash.elements['test-panel-uid'].spec.vizConfig.spec.pluginVersion);
|
||||
expect(vizPanel.state.options).toEqual(dash.elements['test-panel-uid'].spec.vizConfig.spec.options);
|
||||
expect(vizPanel.state.fieldConfig).toEqual(dash.elements['test-panel-uid'].spec.vizConfig.spec.fieldConfig);
|
||||
|
||||
// FIXME: There is an error of data being undefined
|
||||
// expect(vizPanel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
// const dataTransformer = vizPanel.state.$data as SceneDataTransformer;
|
||||
// expect(dataTransformer.state.transformations).toEqual([{ id: 'transform1', options: {} }]);
|
||||
|
||||
// expect(dataTransformer.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
const queryRunner = getQueryRunnerFor(vizPanel);
|
||||
expect(queryRunner).toBeInstanceOf(SceneQueryRunner);
|
||||
expect(queryRunner?.state.datasource).toBeUndefined();
|
||||
// expect(queryRunner.state.queries).toEqual([{ query: 'test-query', datasource: { uid: 'datasource1', type: 'prometheus' } }]);
|
||||
// expect(queryRunner.state.maxDataPoints).toBe(100);
|
||||
// expect(queryRunner.state.cacheTimeout).toBe('1m');
|
||||
// expect(queryRunner.state.queryCachingTTL).toBe(60);
|
||||
// expect(queryRunner.state.minInterval).toBe('1m');
|
||||
// expect(queryRunner.state.dataLayerFilter?.panelId).toBe(1);
|
||||
|
||||
// FIXME: Fix the key incompatibility since panel is not numeric anymore
|
||||
// expect(vizPanel.state.key).toBe(dash.elements['test-panel-uid'].spec.uid);
|
||||
validateVizPanel(vizPanel, dash);
|
||||
|
||||
// FIXME: Tests for layout
|
||||
});
|
||||
|
@ -85,7 +85,7 @@ import {
|
||||
|
||||
const DEFAULT_DATASOURCE = 'default';
|
||||
|
||||
type TypedVariableModelv2 =
|
||||
export type TypedVariableModelV2 =
|
||||
| QueryVariableKind
|
||||
| TextVariableKind
|
||||
| ConstantVariableKind
|
||||
@ -396,7 +396,7 @@ function createVariablesForDashboard(dashboard: DashboardV2Spec) {
|
||||
});
|
||||
}
|
||||
|
||||
function createSceneVariableFromVariableModel(variable: TypedVariableModelv2): SceneVariable {
|
||||
function createSceneVariableFromVariableModel(variable: TypedVariableModelV2): SceneVariable {
|
||||
const commonProperties = {
|
||||
name: variable.spec.name,
|
||||
label: variable.spec.label,
|
||||
@ -593,7 +593,7 @@ export function createVariablesForSnapshot(dashboard: DashboardV2Spec): SceneVar
|
||||
}
|
||||
|
||||
/** Snapshots variables are read-only and should not be updated */
|
||||
export function createSnapshotVariable(variable: TypedVariableModelv2): SceneVariable {
|
||||
export function createSnapshotVariable(variable: TypedVariableModelV2): SceneVariable {
|
||||
let snapshotVariable: SnapshotVariable;
|
||||
let current: { value: string | string[]; text: string | string[] };
|
||||
if (variable.kind === 'IntervalVariable') {
|
||||
|
88
public/app/features/dashboard-scene/v2schema/test-helpers.ts
Normal file
88
public/app/features/dashboard-scene/v2schema/test-helpers.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import {
|
||||
AdHocFiltersVariable,
|
||||
DataSourceVariable,
|
||||
GroupByVariable,
|
||||
QueryVariable,
|
||||
SceneDataTransformer,
|
||||
SceneQueryRunner,
|
||||
SceneVariable,
|
||||
SceneVariableState,
|
||||
VizPanel,
|
||||
} from '@grafana/scenes';
|
||||
import { DashboardV2Spec } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0/dashboard.gen';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { TypedVariableModelV2 } from '../serialization/transformSaveModelSchemaV2ToScene';
|
||||
import { getQueryRunnerFor } from '../utils/utils';
|
||||
|
||||
type SceneVariableConstructor<T extends SceneVariableState, V extends SceneVariable<T>> = new (
|
||||
initialState: Partial<T>
|
||||
) => V;
|
||||
|
||||
interface VariableValidation<T extends TypedVariableModelV2, S extends SceneVariableState, V extends SceneVariable<S>> {
|
||||
sceneVariable: SceneVariable<SceneVariableState> | undefined;
|
||||
variableKind: T;
|
||||
scene: DashboardScene;
|
||||
dashSpec: DashboardV2Spec;
|
||||
sceneVariableClass: SceneVariableConstructor<S, V>;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export function validateVariable<
|
||||
T extends TypedVariableModelV2,
|
||||
S extends SceneVariableState,
|
||||
V extends SceneVariable<S>,
|
||||
>({ sceneVariable, variableKind, scene, dashSpec, sceneVariableClass, index }: VariableValidation<T, S, V>) {
|
||||
if (variableKind.kind === 'AdhocVariable' && sceneVariable instanceof AdHocFiltersVariable) {
|
||||
expect(sceneVariable).toBeInstanceOf(AdHocFiltersVariable);
|
||||
expect(scene.state?.$variables?.getByName(dashSpec.variables[index].spec.name)?.getValue()).toBe(
|
||||
`${variableKind.spec.filters[0].key}="${variableKind.spec.filters[0].value}"`
|
||||
);
|
||||
expect(sceneVariable?.state.datasource).toEqual(variableKind.spec.datasource);
|
||||
} else if (variableKind.kind !== 'AdhocVariable') {
|
||||
expect(sceneVariable).toBeInstanceOf(sceneVariableClass);
|
||||
expect(scene.state?.$variables?.getByName(dashSpec.variables[index].spec.name)?.getValue()).toBe(
|
||||
variableKind.spec.current.value
|
||||
);
|
||||
}
|
||||
if (sceneVariable instanceof DataSourceVariable && variableKind.kind === 'DatasourceVariable') {
|
||||
expect(sceneVariable?.state.pluginId).toBe(variableKind.spec.pluginId);
|
||||
}
|
||||
if (sceneVariable instanceof QueryVariable && variableKind.kind === 'QueryVariable') {
|
||||
expect(sceneVariable?.state.datasource).toBe(variableKind.spec.datasource);
|
||||
expect(sceneVariable?.state.query).toBe(variableKind.spec.query);
|
||||
}
|
||||
if (sceneVariable instanceof GroupByVariable && variableKind.kind === 'CustomVariable') {
|
||||
expect(sceneVariable?.state.datasource).toBe(variableKind.spec.query);
|
||||
}
|
||||
}
|
||||
|
||||
export function validateVizPanel(vizPanel: VizPanel, dash: DashboardV2Spec) {
|
||||
expect(vizPanel.state.title).toBe(dash.elements['test-panel-uid'].spec.title);
|
||||
expect(vizPanel.state.description).toBe(dash.elements['test-panel-uid'].spec.description);
|
||||
expect(vizPanel.state.pluginId).toBe(dash.elements['test-panel-uid'].spec.vizConfig.kind);
|
||||
expect(vizPanel.state.pluginVersion).toBe(dash.elements['test-panel-uid'].spec.vizConfig.spec.pluginVersion);
|
||||
expect(vizPanel.state.options).toEqual(dash.elements['test-panel-uid'].spec.vizConfig.spec.options);
|
||||
expect(vizPanel.state.fieldConfig).toEqual(dash.elements['test-panel-uid'].spec.vizConfig.spec.fieldConfig);
|
||||
expect(vizPanel.state.key).toBe(dash.elements['test-panel-uid'].spec.uid);
|
||||
|
||||
expect(vizPanel.state.$data).toBeInstanceOf(SceneDataTransformer);
|
||||
const dataTransformer = vizPanel.state.$data as SceneDataTransformer;
|
||||
expect(dataTransformer.state.transformations[0]).toEqual(
|
||||
dash.elements['test-panel-uid'].spec.data.spec.transformations[0].spec
|
||||
);
|
||||
|
||||
expect(dataTransformer.state.$data).toBeInstanceOf(SceneQueryRunner);
|
||||
const queryRunner = getQueryRunnerFor(vizPanel)!;
|
||||
expect(queryRunner).toBeInstanceOf(SceneQueryRunner);
|
||||
expect(queryRunner.state.queries).toEqual([
|
||||
{ datasource: { type: 'prometheus', uid: 'datasource1' }, expr: 'test-query', hide: false, refId: 'A' },
|
||||
]);
|
||||
expect(queryRunner.state.maxDataPoints).toBe(100);
|
||||
expect(queryRunner.state.cacheTimeout).toBe('1m');
|
||||
expect(queryRunner.state.queryCachingTTL).toBe(60);
|
||||
expect(queryRunner.state.minInterval).toBe('1m');
|
||||
// FIXME: This is asking for a number as panel ID but here the uid of a panel is string
|
||||
// will be fixed once scenes package is updated to support string panel ID
|
||||
// expect(queryRunner.state.dataLayerFilter?.panelId).toBe(0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user