The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/public/app/features/query/components/QueryEditorRow.test.ts

187 lines
5.6 KiB

import { render, screen } from '@testing-library/react';
import { DataQueryRequest, dateTime, LoadingState, PanelData, toDataFrame } from '@grafana/data';
import { filterPanelDataToQuery, QueryEditorRow } from './QueryEditorRow';
function makePretendRequest(requestId: string, subRequests?: DataQueryRequest[]): DataQueryRequest {
return {
requestId,
// subRequests,
} as DataQueryRequest;
}
describe('filterPanelDataToQuery', () => {
const data: PanelData = {
state: LoadingState.Done,
series: [
toDataFrame({ refId: 'A', fields: [{ name: 'AAA' }], meta: {} }),
toDataFrame({ refId: 'B', fields: [{ name: 'B111' }], meta: {} }),
toDataFrame({ refId: 'B', fields: [{ name: 'B222' }], meta: {} }),
toDataFrame({ refId: 'B', fields: [{ name: 'B333' }], meta: {} }),
toDataFrame({ refId: 'C', fields: [{ name: 'CCCC' }], meta: { requestId: 'sub3' } }),
],
error: {
refId: 'B',
message: 'Error!!',
},
request: makePretendRequest('111', [
makePretendRequest('sub1'),
makePretendRequest('sub2'),
makePretendRequest('sub3'),
]),
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
};
it('should not have an error unless the refId matches', () => {
const panelData = filterPanelDataToQuery(data, 'A');
expect(panelData?.series.length).toBe(1);
expect(panelData?.series[0].refId).toBe('A');
expect(panelData?.error).toBeUndefined();
});
it('should match the error to the query', () => {
const panelData = filterPanelDataToQuery(data, 'B');
expect(panelData?.series.length).toBe(3);
expect(panelData?.series[0].refId).toBe('B');
expect(panelData?.error!.refId).toBe('B');
});
it('should include errors when missing data', () => {
const withError = {
series: [],
error: {
message: 'Error!!',
},
} as unknown as PanelData;
const panelData = filterPanelDataToQuery(withError, 'B');
expect(panelData).toBeDefined();
expect(panelData?.state).toBe(LoadingState.Error);
expect(panelData?.error).toBe(withError.error);
});
it('should set the state to done if the frame has no errors', () => {
const withError = {
...data,
};
withError.state = LoadingState.Error;
const panelDataB = filterPanelDataToQuery(withError, 'B');
expect(panelDataB?.series.length).toBe(3);
expect(panelDataB?.series[0].refId).toBe('B');
expect(panelDataB?.state).toBe(LoadingState.Error);
const panelDataA = filterPanelDataToQuery(withError, 'A');
expect(panelDataA?.series.length).toBe(1);
expect(panelDataA?.series[0].refId).toBe('A');
expect(panelDataA?.state).toBe(LoadingState.Done);
});
it('should return error for query that returns no data, but another query does return data', () => {
const withError = {
...data,
state: LoadingState.Error,
error: {
message: 'Sad',
refId: 'Q',
},
};
const panelDataB = filterPanelDataToQuery(withError, 'Q');
expect(panelDataB?.series.length).toBe(0);
expect(panelDataB?.error?.refId).toBe('Q');
});
it('should not set the state to done if the frame is loading and has no errors', () => {
const loadingData: PanelData = {
state: LoadingState.Loading,
series: [
toDataFrame({ refId: 'A', fields: [{ name: 'AAA' }], meta: {} }),
toDataFrame({ refId: 'B', fields: [{ name: 'B111' }], meta: {} }),
],
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
};
const panelDataB = filterPanelDataToQuery(loadingData, 'B');
expect(panelDataB?.state).toBe(LoadingState.Loading);
const panelDataA = filterPanelDataToQuery(loadingData, 'A');
expect(panelDataA?.state).toBe(LoadingState.Loading);
});
});
describe('frame results with warnings', () => {
const meta = {
notices: [
{
severity: 'warning',
text: 'Reduce operation is not needed. Input query or expression A is already reduced data.',
},
],
};
const dataWithWarnings: PanelData = {
state: LoadingState.Done,
series: [
toDataFrame({
refId: 'B',
fields: [{ name: 'B1' }],
meta,
}),
toDataFrame({
refId: 'B',
fields: [{ name: 'B2' }],
meta,
}),
],
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
};
const dataWithoutWarnings: PanelData = {
state: LoadingState.Done,
series: [
toDataFrame({
refId: 'B',
fields: [{ name: 'B1' }],
meta: {},
}),
toDataFrame({
refId: 'B',
fields: [{ name: 'B2' }],
meta: {},
}),
],
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
};
it('should show a warning badge and de-duplicate warning messages', () => {
// @ts-ignore: there are _way_ too many props to inject here :(
const editorRow = new QueryEditorRow({
data: dataWithWarnings,
query: {
refId: 'B',
},
});
const warningsComponent = editorRow.renderWarnings();
expect(warningsComponent).not.toBe(null);
render(warningsComponent!);
expect(screen.getByText('1 warning')).toBeInTheDocument();
});
it('should not show a warning badge when there are no warnings', () => {
// @ts-ignore: there are _way_ too many props to inject here :(
const editorRow = new QueryEditorRow({
data: dataWithoutWarnings,
query: {
refId: 'B',
},
});
const warningsComponent = editorRow.renderWarnings();
expect(warningsComponent).toBe(null);
});
});