Files
grafana/public/app/plugins/datasource/prometheus/configuration/PromSettings.test.tsx
T
Nick Richmond 559fab9dc6 Prometheus: Fuzzy search for metric names in Code Mode (#85396)
* perf: limit metric names in Code Mode suggestions

* feat: configurable metric names limit

* feat: code mode autocomplete info/disclaimer

* chore: put new functionality behind new feature toggle

* refactor: avoid type assertions

* refactor: avoid explicit `any`

refactor: type guards

* refactor: type guards

* chore: add testdata results

* fix: add missing feature toggle guard

* perf: prefer array access to `Array.prototype.at`

* test: add missing config override

* test: refactor for brevity & clarity

* perf: avoid unnecessary mapping

* chore: undo testdata changes

* fix: use correct limit; perf optimizations

* refactor: avoid unnecessary `async`s

* types: simplify

* test: add missing tests

* fix: avoid hardcoding

* test: update mock path

* docs: fix typo

style: remove formatting artifact

style: remove formatting artifact

style: remove formatting artifact

* fix: event scope regression

* style: refactor for clarity

* refactor: prefer `useCallback` to in-effect handler

* refactor: simplify & broaden `filter`

* refactor: rename file to keep with conventions

* chore: mirror Prometheus package changes in app

* refactor: prefer no `@ts-ignore`

* chore: update betterer results

* docs: use type in TSDoc `@link` without `@ts-ignore`

* test: add missing provider

* test: fix jest mock path

* fix: display disclaimer in empty input case
2024-04-04 23:38:23 +03:00

143 lines
4.9 KiB
TypeScript

import { render, screen, fireEvent } from '@testing-library/react';
import React, { SyntheticEvent } from 'react';
import { Provider } from 'react-redux';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
import { configureStore } from '../../../../store/configureStore';
import { countError, getValueFromEventItem, PromSettings } from './PromSettings';
import { createDefaultConfigOptions } from './mocks';
beforeEach(() => {
jest.replaceProperty(config, 'featureToggles', {
prometheusCodeModeMetricNamesSearch: true,
});
});
describe('PromSettings', () => {
describe('getValueFromEventItem', () => {
describe('when called with undefined', () => {
it('then it should return empty string', () => {
const result = getValueFromEventItem(
undefined as unknown as SyntheticEvent<HTMLInputElement> | SelectableValue<string>
);
expect(result).toEqual('');
});
});
describe('when called with an input event', () => {
it('then it should return value from currentTarget', () => {
const value = 'An input value';
const result = getValueFromEventItem({ currentTarget: { value } });
expect(result).toEqual(value);
});
});
describe('when called with a select event', () => {
it('then it should return value', () => {
const value = 'A select value';
const result = getValueFromEventItem({ value });
expect(result).toEqual(value);
});
});
});
describe('PromSettings component', () => {
const defaultProps = createDefaultConfigOptions();
it('should show POST httpMethod if no httpMethod', () => {
const options = defaultProps;
options.url = '';
options.jsonData.httpMethod = '';
const store = configureStore();
render(
<Provider store={store}>
<PromSettings onOptionsChange={() => {}} options={options} />
</Provider>
);
expect(screen.getByText('POST')).toBeInTheDocument();
});
it('should show POST httpMethod if POST httpMethod is configured', () => {
const options = defaultProps;
options.url = 'test_url';
options.jsonData.httpMethod = 'POST';
const store = configureStore();
render(
<Provider store={store}>
<PromSettings onOptionsChange={() => {}} options={options} />
</Provider>
);
expect(screen.getByText('POST')).toBeInTheDocument();
});
it('should show GET httpMethod if GET httpMethod is configured', () => {
const options = defaultProps;
options.url = 'test_url';
options.jsonData.httpMethod = 'GET';
const store = configureStore();
render(
<Provider store={store}>
<PromSettings onOptionsChange={() => {}} options={options} />
</Provider>
);
expect(screen.getByText('GET')).toBeInTheDocument();
});
it('should show a valid metric name count if codeModeMetricNamesSuggestionLimit is configured correctly', () => {
const options = defaultProps;
const store = configureStore();
const { getByTestId, queryByText } = render(
<Provider store={store}>
<PromSettings onOptionsChange={() => {}} options={options} />
</Provider>
);
const input = getByTestId(
selectors.components.DataSource.Prometheus.configPage.codeModeMetricNamesSuggestionLimit
);
// Non-negative integer
fireEvent.change(input, { target: { value: '3000' } });
fireEvent.blur(input);
expect(queryByText(countError)).not.toBeInTheDocument();
// Non-negative integer with scientific notation
fireEvent.change(input, { target: { value: '1e5' } });
fireEvent.blur(input);
expect(queryByText(countError)).not.toBeInTheDocument();
// Non-negative integer with decimal scientific notation
fireEvent.change(input, { target: { value: '1.4e4' } });
fireEvent.blur(input);
expect(queryByText(countError)).not.toBeInTheDocument();
});
it('should show the expected error when an invalid value is provided for codeModeMetricNamesSuggestionLimit', () => {
const options = defaultProps;
const store = configureStore();
const { getByTestId, queryByText } = render(
<Provider store={store}>
<PromSettings onOptionsChange={() => {}} options={options} />
</Provider>
);
const input = getByTestId(
selectors.components.DataSource.Prometheus.configPage.codeModeMetricNamesSuggestionLimit
);
// No negative values
fireEvent.change(input, { target: { value: '-50' } });
fireEvent.blur(input);
expect(queryByText(countError)).toBeInTheDocument();
// No negative values with scientific notation
fireEvent.change(input, { target: { value: '-5e5' } });
fireEvent.blur(input);
expect(queryByText(countError)).toBeInTheDocument();
});
});
});