grafana_bak/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx
2025-04-01 10:38:02 +09:00

265 lines
9.0 KiB
TypeScript

import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { select } from 'react-select-event';
import { TimeRange, dateTime } from '@grafana/data';
import { TemplateSrv } from '@grafana/runtime';
import { createLokiDatasource } from '../__mocks__/datasource';
import { LokiVariableQueryType } from '../types';
import { LokiVariableQueryEditor, Props } from './VariableQueryEditor';
const refId = 'LokiVariableQueryEditor-VariableQuery';
describe('LokiVariableQueryEditor', () => {
let props: Props;
beforeEach(() => {
props = {
datasource: createLokiDatasource({} as unknown as TemplateSrv),
query: {
refId: 'test',
type: LokiVariableQueryType.LabelNames,
},
onRunQuery: () => {},
onChange: () => {},
};
jest.spyOn(props.datasource.languageProvider, 'fetchLabels').mockResolvedValue(['luna', 'moon']);
});
test('Allows to create a Label names variable', async () => {
const onChange = jest.fn();
render(<LokiVariableQueryEditor {...props} onChange={onChange} />);
expect(onChange).not.toHaveBeenCalled();
await select(screen.getByLabelText('Query type'), 'Label names', { container: document.body });
expect(onChange).toHaveBeenCalledWith({
type: LokiVariableQueryType.LabelNames,
label: '',
stream: '',
refId,
});
});
test('Allows to create a Label values variable', async () => {
const onChange = jest.fn();
render(<LokiVariableQueryEditor {...props} onChange={onChange} />);
expect(onChange).not.toHaveBeenCalled();
await waitFor(() => select(screen.getByLabelText('Query type'), 'Label values', { container: document.body }));
await select(screen.getByLabelText('Label'), 'luna', { container: document.body });
await userEvent.type(screen.getByLabelText('Stream selector'), 'stream');
await waitFor(() => expect(screen.getByDisplayValue('stream')).toBeInTheDocument());
await userEvent.click(document.body);
expect(onChange).toHaveBeenCalledWith({
type: LokiVariableQueryType.LabelValues,
label: 'luna',
stream: 'stream',
refId,
});
});
test('Allows to create a Label values variable with custom label', async () => {
const onChange = jest.fn();
render(<LokiVariableQueryEditor {...props} onChange={onChange} />);
expect(onChange).not.toHaveBeenCalled();
await waitFor(() => select(screen.getByLabelText('Query type'), 'Label values', { container: document.body }));
await userEvent.type(screen.getByLabelText('Label'), 'sol{enter}');
await userEvent.type(screen.getByLabelText('Stream selector'), 'stream');
await waitFor(() => expect(screen.getByDisplayValue('stream')).toBeInTheDocument());
await userEvent.click(document.body);
expect(onChange).toHaveBeenCalledWith({
type: LokiVariableQueryType.LabelValues,
label: 'sol',
stream: 'stream',
refId,
});
});
test('Migrates legacy string queries to LokiVariableQuery instances', async () => {
const query = 'label_values(log stream selector, luna)';
// @ts-expect-error
render(<LokiVariableQueryEditor {...props} onChange={() => {}} query={query} />);
await waitFor(() => expect(screen.getByText('Label values')).toBeInTheDocument());
await waitFor(() => expect(screen.getByText('luna')).toBeInTheDocument());
await waitFor(() => expect(screen.getByDisplayValue('log stream selector')).toBeInTheDocument());
});
test('Receives a query instance and assigns its values when editing', async () => {
render(
<LokiVariableQueryEditor
{...props}
onChange={() => {}}
query={{
type: LokiVariableQueryType.LabelValues,
label: 'luna',
stream: 'log stream selector',
refId,
}}
/>
);
await waitFor(() => expect(screen.getByText('Label values')).toBeInTheDocument());
await waitFor(() => expect(screen.getByText('luna')).toBeInTheDocument());
await waitFor(() => expect(screen.getByDisplayValue('log stream selector')).toBeInTheDocument());
});
test('Label options are not lost when selecting one', async () => {
const { rerender } = render(<LokiVariableQueryEditor {...props} onChange={() => {}} />);
await waitFor(() => select(screen.getByLabelText('Query type'), 'Label values', { container: document.body }));
await select(screen.getByLabelText('Label'), 'luna', { container: document.body });
const updatedQuery = {
refId: 'test',
type: LokiVariableQueryType.LabelValues,
label: 'luna',
};
rerender(<LokiVariableQueryEditor {...props} query={updatedQuery} onChange={() => {}} />);
await select(screen.getByLabelText('Label'), 'moon', { container: document.body });
await select(screen.getByLabelText('Label'), 'luna', { container: document.body });
await screen.findByText('luna');
});
test('Calls language provider fetchLabels with the time range received in props', async () => {
const now = dateTime('2023-09-16T21:26:00Z');
const range: TimeRange = {
from: dateTime(now).subtract(2, 'days'),
to: now,
raw: {
from: 'now-2d',
to: 'now',
},
};
props.range = range;
props.query = {
refId: 'test',
type: LokiVariableQueryType.LabelValues,
label: 'luna',
};
render(<LokiVariableQueryEditor {...props} />);
await waitFor(() =>
expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledWith({ timeRange: range })
);
});
test('does not re-run fetch labels when type does not change', async () => {
const now = dateTime('2023-09-16T21:26:00Z');
const range: TimeRange = {
from: dateTime(now).subtract(2, 'days'),
to: now,
raw: {
from: 'now-2d',
to: 'now',
},
};
props.range = range;
props.query = {
refId: 'test',
type: LokiVariableQueryType.LabelValues,
};
props.datasource.languageProvider.fetchLabels = jest.fn().mockResolvedValue([]);
const { rerender } = render(<LokiVariableQueryEditor {...props} />);
rerender(
<LokiVariableQueryEditor {...props} query={{ ...props.query, type: LokiVariableQueryType.LabelValues }} />
);
await waitFor(() => {
expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1);
});
});
test('runs fetch labels when type changes to from LabelNames to LabelValues', async () => {
const now = dateTime('2023-09-16T21:26:00Z');
const range: TimeRange = {
from: dateTime(now).subtract(2, 'days'),
to: now,
raw: {
from: 'now-2d',
to: 'now',
},
};
props.range = range;
props.query = {
refId: 'test',
type: LokiVariableQueryType.LabelNames,
};
props.datasource.languageProvider.fetchLabels = jest.fn().mockResolvedValue([]);
const { rerender } = render(<LokiVariableQueryEditor {...props} />);
rerender(
<LokiVariableQueryEditor {...props} query={{ ...props.query, type: LokiVariableQueryType.LabelValues }} />
);
await waitFor(() => {
expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1);
});
});
test('runs fetch labels when type changes to LabelValues', async () => {
const now = dateTime('2023-09-16T21:26:00Z');
const range: TimeRange = {
from: dateTime(now).subtract(2, 'days'),
to: now,
raw: {
from: 'now-2d',
to: 'now',
},
};
props.range = range;
props.query = {
refId: 'test',
type: LokiVariableQueryType.LabelNames,
};
props.datasource.languageProvider.fetchLabels = jest.fn().mockResolvedValue([]);
// Starting with LabelNames
const { rerender } = render(<LokiVariableQueryEditor {...props} />);
// Changing to LabelValues, should run fetchLabels
rerender(
<LokiVariableQueryEditor {...props} query={{ ...props.query, type: LokiVariableQueryType.LabelValues }} />
);
await waitFor(() => {
expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1);
});
// Keeping the type of LabelValues, should not run additional fetchLabels
rerender(
<LokiVariableQueryEditor {...props} query={{ ...props.query, type: LokiVariableQueryType.LabelValues }} />
);
await waitFor(() => {
expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1);
});
// Changing to LabelNames, should not run additional fetchLabels
rerender(<LokiVariableQueryEditor {...props} query={{ ...props.query, type: LokiVariableQueryType.LabelNames }} />);
await waitFor(() => {
expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(1);
});
// Changing to LabelValues, should run additional fetchLabels
rerender(
<LokiVariableQueryEditor {...props} query={{ ...props.query, type: LokiVariableQueryType.LabelValues }} />
);
await waitFor(() => {
expect(props.datasource.languageProvider.fetchLabels).toHaveBeenCalledTimes(2);
});
});
});