add tests

This commit is contained in:
Develer
2025-12-16 20:01:16 +01:00
parent 59cbd4c7d8
commit af9a0d3598
2 changed files with 271 additions and 2 deletions
@@ -117,4 +117,102 @@ describe('EmptyTransformationsMessage', () => {
expect(screen.getByTestId(selectors.components.Transforms.addTransformationButton)).toBeInTheDocument();
});
});
describe('SQL card disabled state', () => {
beforeEach(() => {
config.featureToggles.transformationsEmptyPlaceholder = true;
config.featureToggles.sqlExpressions = true;
});
// Helper to check if the info icon button is present (rendered when disabled)
const getInfoIconButton = (container: HTMLElement) => {
// The IconButton for info renders as a button with an SVG icon
// When disabled, there are 2 buttons: the card button and the info icon button
const buttons = container.querySelectorAll('button');
return buttons.length > 1 ? buttons[1] : null;
};
it('should show disabled SQL card with info icon when isSqlApplicable is false', () => {
render(
<EmptyTransformationsMessage
onShowPicker={onShowPicker}
onGoToQueries={onGoToQueries}
onAddTransformation={onAddTransformation}
isSqlApplicable={false}
/>
);
const sqlCard = screen.getByTestId('go-to-queries-button');
// Should show info icon button when disabled (2 buttons total)
expect(getInfoIconButton(sqlCard)).toBeInTheDocument();
});
it('should not call onGoToQueries when SQL card is disabled and clicked', async () => {
const user = userEvent.setup();
render(
<EmptyTransformationsMessage
onShowPicker={onShowPicker}
onGoToQueries={onGoToQueries}
onAddTransformation={onAddTransformation}
isSqlApplicable={false}
/>
);
const sqlCard = screen.getByTestId('go-to-queries-button');
const button = sqlCard.querySelector('button');
await user.click(button!);
// onGoToQueries should NOT be called when disabled
expect(onGoToQueries).not.toHaveBeenCalled();
});
it('should call onGoToQueries when SQL card is enabled and clicked', async () => {
const user = userEvent.setup();
render(
<EmptyTransformationsMessage
onShowPicker={onShowPicker}
onGoToQueries={onGoToQueries}
onAddTransformation={onAddTransformation}
isSqlApplicable={true}
/>
);
const sqlCard = screen.getByTestId('go-to-queries-button');
const button = sqlCard.querySelector('button');
await user.click(button!);
expect(onGoToQueries).toHaveBeenCalledTimes(1);
});
it('should not show info icon when SQL card is enabled', () => {
render(
<EmptyTransformationsMessage
onShowPicker={onShowPicker}
onGoToQueries={onGoToQueries}
onAddTransformation={onAddTransformation}
isSqlApplicable={true}
/>
);
const sqlCard = screen.getByTestId('go-to-queries-button');
// Should NOT show info icon button when enabled (only 1 button)
expect(getInfoIconButton(sqlCard)).toBeNull();
});
it('should default to enabled when isSqlApplicable is not provided', () => {
render(
<EmptyTransformationsMessage
onShowPicker={onShowPicker}
onGoToQueries={onGoToQueries}
onAddTransformation={onAddTransformation}
/>
);
const sqlCard = screen.getByTestId('go-to-queries-button');
// Should NOT show info icon button when default (enabled)
expect(getInfoIconButton(sqlCard)).toBeNull();
});
});
});
@@ -11,9 +11,11 @@ import {
toDataFrame,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { DataSourceSrv, getDataSourceSrv } from '@grafana/runtime';
import { SceneDataTransformer, SceneQueryRunner } from '@grafana/scenes';
import config from 'app/core/config';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { ExpressionDatasourceUID } from 'app/features/expressions/types';
import { getStandardTransformers } from 'app/features/transformers/standardTransformers';
import { DashboardDataDTO } from 'app/types/dashboard';
@@ -24,14 +26,40 @@ import { testDashboard } from '../testfiles/testDashboard';
import { PanelDataTransformationsTab, PanelDataTransformationsTabRendered } from './PanelDataTransformationsTab';
// Mock getDataSourceSrv
jest.mock('@grafana/runtime', () => {
const actual = jest.requireActual('@grafana/runtime');
return {
...actual,
getDataSourceSrv: jest.fn(() => ({
getInstanceSettings: jest.fn(),
})),
};
});
const getDataSourceSrvMock = getDataSourceSrv as jest.MockedFunction<typeof getDataSourceSrv>;
// Helper to create DataSourceSrv mock with custom getInstanceSettings
const createMockDataSourceSrv = (
getInstanceSettingsFn: (ref: { uid?: string; type?: string } | undefined) => unknown
): DataSourceSrv =>
({
get: jest.fn(),
getList: jest.fn(),
getInstanceSettings: getInstanceSettingsFn,
reload: jest.fn(),
registerRuntimeDataSource: jest.fn(),
}) as unknown as DataSourceSrv;
function createModelMock(
panelData: PanelData,
transformations?: DataTransformerConfig[],
onChangeTransformationsMock?: Function
onChangeTransformationsMock?: Function,
queries: Array<{ refId: string; datasource?: { uid?: string; type?: string } }> = []
) {
return {
getDataTransformer: () => new SceneDataTransformer({ data: panelData, transformations: transformations || [] }),
getQueryRunner: () => new SceneQueryRunner({ queries: [], data: panelData }),
getQueryRunner: () => new SceneQueryRunner({ queries, data: panelData }),
onChangeTransformations: onChangeTransformationsMock,
} as unknown as PanelDataTransformationsTab;
}
@@ -208,6 +236,149 @@ describe('PanelDataTransformationsTab', () => {
});
});
describe('SQL Expression applicability', () => {
standardTransformersRegistry.setInit(getStandardTransformers);
let originalTransformationsToggle: boolean | undefined;
let originalSqlToggle: boolean | undefined;
beforeEach(() => {
originalTransformationsToggle = config.featureToggles.transformationsEmptyPlaceholder;
originalSqlToggle = config.featureToggles.sqlExpressions;
config.featureToggles.transformationsEmptyPlaceholder = true;
config.featureToggles.sqlExpressions = true;
});
afterEach(() => {
config.featureToggles.transformationsEmptyPlaceholder = originalTransformationsToggle;
config.featureToggles.sqlExpressions = originalSqlToggle;
jest.clearAllMocks();
});
// Helper to check if the info icon button is present (rendered when disabled)
// The IconButton for info renders as a button with an SVG icon
// When disabled, there are 2 buttons: the card button and the info icon button
const getInfoIconButton = (container: HTMLElement) => {
const buttons = container.querySelectorAll('button');
return buttons.length > 1 ? buttons[1] : null;
};
it('should enable SQL card when datasource is a backend datasource', async () => {
getDataSourceSrvMock.mockReturnValue(
createMockDataSourceSrv(() => ({
uid: 'prometheus',
name: 'Prometheus',
meta: { backend: true },
}))
);
const modelMock = createModelMock(mockData, [], undefined, [
{ refId: 'A', datasource: { uid: 'prometheus', type: 'prometheus' } },
]);
render(<PanelDataTransformationsTabRendered model={modelMock} />);
const sqlCard = await screen.findByTestId('go-to-queries-button');
// Card should NOT have disabled background styling - check it's clickable
expect(sqlCard).toBeInTheDocument();
// The card should not show the disabled info icon button
expect(getInfoIconButton(sqlCard)).toBeNull();
});
it('should disable SQL card when datasource is frontend-only', async () => {
getDataSourceSrvMock.mockReturnValue(
createMockDataSourceSrv(() => ({
uid: 'googlesheets',
name: 'Google Sheets',
meta: { backend: false, isBackend: false },
}))
);
const modelMock = createModelMock(mockData, [], undefined, [
{ refId: 'A', datasource: { uid: 'googlesheets', type: 'grafana-googlesheets-datasource' } },
]);
render(<PanelDataTransformationsTabRendered model={modelMock} />);
const sqlCard = await screen.findByTestId('go-to-queries-button');
// Card should show the disabled info icon button
expect(getInfoIconButton(sqlCard)).toBeInTheDocument();
});
it('should enable SQL card when datasource settings cannot be found', async () => {
// Return undefined for getInstanceSettings - simulating unknown datasource
getDataSourceSrvMock.mockReturnValue(createMockDataSourceSrv(() => undefined));
const modelMock = createModelMock(mockData, [], undefined, [
{ refId: 'A', datasource: { uid: 'unknown-ds', type: 'unknown' } },
]);
render(<PanelDataTransformationsTabRendered model={modelMock} />);
const sqlCard = await screen.findByTestId('go-to-queries-button');
// Card should NOT be disabled when we can't determine datasource type
expect(getInfoIconButton(sqlCard)).toBeNull();
});
it('should skip expression queries when checking SQL applicability', async () => {
getDataSourceSrvMock.mockReturnValue(
createMockDataSourceSrv((ref) => {
if (ref?.uid === ExpressionDatasourceUID) {
// Expression datasource - this should be skipped
return { uid: ExpressionDatasourceUID, name: 'Expression', meta: { backend: false } };
}
// Backend datasource
return { uid: 'prometheus', name: 'Prometheus', meta: { backend: true } };
})
);
const modelMock = createModelMock(mockData, [], undefined, [
{ refId: 'A', datasource: { uid: 'prometheus', type: 'prometheus' } },
{ refId: 'B', datasource: { uid: ExpressionDatasourceUID, type: '__expr__' } }, // Expression query
]);
render(<PanelDataTransformationsTabRendered model={modelMock} />);
const sqlCard = await screen.findByTestId('go-to-queries-button');
// Should still be enabled because expression queries are skipped
expect(getInfoIconButton(sqlCard)).toBeNull();
});
it('should disable SQL card if any non-expression query uses frontend-only datasource', async () => {
getDataSourceSrvMock.mockReturnValue(
createMockDataSourceSrv((ref) => {
if (ref?.uid === 'googlesheets') {
return { uid: 'googlesheets', name: 'Google Sheets', meta: { backend: false, isBackend: false } };
}
return { uid: 'prometheus', name: 'Prometheus', meta: { backend: true } };
})
);
const modelMock = createModelMock(mockData, [], undefined, [
{ refId: 'A', datasource: { uid: 'prometheus', type: 'prometheus' } },
{ refId: 'B', datasource: { uid: 'googlesheets', type: 'grafana-googlesheets-datasource' } },
]);
render(<PanelDataTransformationsTabRendered model={modelMock} />);
const sqlCard = await screen.findByTestId('go-to-queries-button');
// Card should be disabled because one datasource is frontend-only
expect(getInfoIconButton(sqlCard)).toBeInTheDocument();
});
it('should enable SQL card when there are no queries', async () => {
getDataSourceSrvMock.mockReturnValue(createMockDataSourceSrv(() => undefined));
const modelMock = createModelMock(mockData, [], undefined, []);
render(<PanelDataTransformationsTabRendered model={modelMock} />);
const sqlCard = await screen.findByTestId('go-to-queries-button');
// Card should be enabled when there are no queries
expect(getInfoIconButton(sqlCard)).toBeNull();
});
});
function setupTabScene(panelId: string) {
const scene = transformSaveModelToScene({ dashboard: testDashboard as unknown as DashboardDataDTO, meta: {} });
const panel = findVizPanelByKey(scene, panelId)!;