Files
Ivana Huckova c23bc1e7b7 Prometheus: Show variable options in query builder (#44784)
* Prometheus: Show variable options

* Remove lint error

* Fix test for CodeQL

* Update public/app/plugins/datasource/prometheus/datasource.ts

Co-authored-by: Torkel Ödegaard <torkel@grafana.org>

* Update public/app/plugins/datasource/loki/datasource.ts

Co-authored-by: Torkel Ödegaard <torkel@grafana.org>

Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
2022-02-03 11:40:19 +01:00

169 lines
5.3 KiB
TypeScript

import React from 'react';
import { render, screen, getByRole, getByText } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { PromQueryBuilder } from './PromQueryBuilder';
import { PrometheusDatasource } from '../../datasource';
import { EmptyLanguageProviderMock } from '../../language_provider.mock';
import PromQlLanguageProvider from '../../language_provider';
import { PromVisualQuery } from '../types';
import { getLabelSelects } from '../testUtils';
const defaultQuery: PromVisualQuery = {
metric: 'random_metric',
labels: [],
operations: [],
};
const bugQuery: PromVisualQuery = {
metric: 'random_metric',
labels: [{ label: 'instance', op: '=', value: 'localhost:9090' }],
operations: [
{
id: 'rate',
params: ['auto'],
},
{
id: '__sum_by',
params: ['instance', 'job'],
},
],
binaryQueries: [
{
operator: '/',
query: {
metric: 'metric2',
labels: [{ label: 'foo', op: '=', value: 'bar' }],
operations: [
{
id: '__sum_by',
params: ['app'],
},
],
},
},
],
};
describe('PromQueryBuilder', () => {
it('shows empty just with metric selected', async () => {
setup();
// One should be select another query preview
expect(screen.getAllByText('random_metric').length).toBe(2);
// Add label
expect(screen.getByLabelText('Add')).toBeInTheDocument();
expect(screen.getByLabelText('Add operation')).toBeInTheDocument();
});
it('renders all the query sections', async () => {
setup(bugQuery);
expect(screen.getByText('random_metric')).toBeInTheDocument();
expect(screen.getByText('localhost:9090')).toBeInTheDocument();
expect(screen.getByText('Rate')).toBeInTheDocument();
const sumBys = screen.getAllByTestId('operation-wrapper-for-__sum_by');
expect(getByText(sumBys[0], 'instance')).toBeInTheDocument();
expect(getByText(sumBys[0], 'job')).toBeInTheDocument();
expect(getByText(sumBys[1], 'app')).toBeInTheDocument();
expect(screen.getByText('Binary operations')).toBeInTheDocument();
expect(screen.getByText('Operator')).toBeInTheDocument();
expect(screen.getByText('Vector matches')).toBeInTheDocument();
expect(screen.getByLabelText('selector').textContent).toBe(
'sum by(instance, job) (rate(random_metric{instance="localhost:9090"}[$__rate_interval])) / sum by(app) (metric2{foo="bar"})'
);
});
it('tries to load metrics without labels', async () => {
const { languageProvider } = setup();
openMetricSelect();
expect(languageProvider.getLabelValues).toBeCalledWith('__name__');
});
it('tries to load metrics with labels', async () => {
const { languageProvider } = setup({
...defaultQuery,
labels: [{ label: 'label_name', op: '=', value: 'label_value' }],
});
openMetricSelect();
expect(languageProvider.getSeries).toBeCalledWith('{label_name="label_value"}', true);
});
it('tries to load variables in metric field', async () => {
const { datasource } = setup();
datasource.getVariables = jest.fn().mockReturnValue([]);
openMetricSelect();
expect(datasource.getVariables).toBeCalled();
});
it('tries to load labels when metric selected', async () => {
const { languageProvider } = setup();
openLabelNameSelect();
expect(languageProvider.fetchSeriesLabels).toBeCalledWith('{__name__="random_metric"}');
});
it('tries to load variables in label field', async () => {
const { datasource } = setup();
datasource.getVariables = jest.fn().mockReturnValue([]);
openLabelNameSelect();
expect(datasource.getVariables).toBeCalled();
});
it('tries to load labels when metric selected and other labels are already present', async () => {
const { languageProvider } = setup({
...defaultQuery,
labels: [
{ label: 'label_name', op: '=', value: 'label_value' },
{ label: 'foo', op: '=', value: 'bar' },
],
});
openLabelNameSelect(1);
expect(languageProvider.fetchSeriesLabels).toBeCalledWith('{label_name="label_value", __name__="random_metric"}');
});
it('tries to load labels when metric is not selected', async () => {
const { languageProvider } = setup({
...defaultQuery,
metric: '',
});
openLabelNameSelect();
expect(languageProvider.fetchLabels).toBeCalled();
});
});
function setup(query: PromVisualQuery = defaultQuery) {
const languageProvider = new EmptyLanguageProviderMock() as unknown as PromQlLanguageProvider;
const datasource = new PrometheusDatasource(
{
url: '',
jsonData: {},
meta: {} as any,
} as any,
undefined,
undefined,
languageProvider
);
const props = {
datasource,
onRunQuery: () => {},
onChange: () => {},
};
render(<PromQueryBuilder {...props} query={query} />);
return { languageProvider, datasource };
}
function getMetricSelect() {
const metricSelect = screen.getAllByText('random_metric')[0].parentElement!;
// We need to return specifically input element otherwise clicks don't seem to work
return getByRole(metricSelect, 'combobox');
}
function openMetricSelect() {
const select = getMetricSelect();
userEvent.click(select);
}
function openLabelNameSelect(index = 0) {
const { name } = getLabelSelects(index);
userEvent.click(name);
}