mirror of https://github.com/grafana/grafana.git
Select: Portal select menu to document.body (#36398)
* ValueMappings: Force overflowing modal content to scroll * ValueMappings: Update unit tests * Select: Portal Select to document.body, close menu on scroll * Select: Fix tests + apply updates from https://github.com/grafana/grafana/pull/32833 * ValueMappingsEditorModal: Revert to using selectEvent in the tests * Select: Fix remaining unit tests * Portal: Rewrite Portal as a functional component so we can use useTheme2 * Modal: Remove modal styles from this PR * Update E2E tests * More unit test fixes * Select: Fix remaining E2E tests * Select: Create util method to select an option in tests
This commit is contained in:
parent
f41f00dec4
commit
54f8996acf
|
|
@ -15,10 +15,10 @@ export const smokeTestScenario = {
|
|||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().should('be.visible').click();
|
||||
|
||||
cy.contains('CSV Metric Values').scrollIntoView().should('be.visible').click();
|
||||
});
|
||||
|
||||
cy.contains('CSV Metric Values').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// Make sure the graph renders via checking legend
|
||||
e2e.components.VizLegend.seriesName('A-series').should('be.visible');
|
||||
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ e2e.scenario({
|
|||
e2e.components.Select.singleValue().should('be.visible').should('have.text', fromTimeZone);
|
||||
|
||||
e2e.components.Select.input().should('be.visible').click();
|
||||
|
||||
e2e.components.Select.option().should('be.visible').contains(toTimeZone).click();
|
||||
});
|
||||
|
||||
e2e.components.Select.option().should('be.visible').contains(toTimeZone).click();
|
||||
|
||||
// click to go back to the dashboard.
|
||||
e2e.components.BackButton.backArrow().click({ force: true }).wait(2000);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const dataSourceName = 'PromExemplar';
|
|||
const addDataSource = () => {
|
||||
e2e.flows.addDataSource({
|
||||
type: 'Prometheus',
|
||||
expectedAlertMessage: 'HTTP error Bad Gateway',
|
||||
expectedAlertMessage: 'Bad Gateway',
|
||||
name: dataSourceName,
|
||||
form: () => {
|
||||
e2e.components.DataSource.Prometheus.configPage.exemplarsAddButton().click();
|
||||
|
|
@ -13,9 +13,9 @@ const addDataSource = () => {
|
|||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().should('be.visible').click({ force: true });
|
||||
|
||||
e2e().contains('gdev-tempo').scrollIntoView().should('be.visible').click();
|
||||
});
|
||||
|
||||
e2e().contains('gdev-tempo').scrollIntoView().should('be.visible').click();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -54,9 +54,8 @@ describe('Exemplars', () => {
|
|||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().should('be.visible').click();
|
||||
|
||||
e2e().contains(dataSourceName).scrollIntoView().should('be.visible').click();
|
||||
});
|
||||
e2e().contains(dataSourceName).scrollIntoView().should('be.visible').click();
|
||||
e2e.components.TimePicker.openButton().click();
|
||||
e2e.components.TimePicker.fromField().clear().type('2021-05-11 19:30:00');
|
||||
e2e.components.TimePicker.toField().clear().type('2021-05-11 21:40:00');
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ e2e.scenario({
|
|||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().should('be.visible').click();
|
||||
|
||||
cy.contains('CSV Metric Values').scrollIntoView().should('be.visible').click();
|
||||
});
|
||||
|
||||
cy.contains('CSV Metric Values').scrollIntoView().should('be.visible').click();
|
||||
|
||||
const canvases = e2e().get('canvas');
|
||||
canvases.should('have.length', 1);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ e2e.scenario({
|
|||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().eq(0).should('be.visible').click();
|
||||
|
||||
cy.contains('CSV Metric Values').scrollIntoView().should('be.visible').eq(0).click();
|
||||
});
|
||||
|
||||
cy.contains('CSV Metric Values').scrollIntoView().should('be.visible').eq(0).click();
|
||||
|
||||
// Disable / enable row
|
||||
expectInspectorResultAndClose((keys) => {
|
||||
const length = keys.length;
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ e2e.scenario({
|
|||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().should('be.visible').click();
|
||||
|
||||
cy.contains('gdev-prometheus').scrollIntoView().should('be.visible').click();
|
||||
});
|
||||
|
||||
cy.contains('gdev-prometheus').scrollIntoView().should('be.visible').click();
|
||||
const queryText = 'http_requests_total';
|
||||
|
||||
e2e.components.QueryField.container().should('be.visible').type(queryText).type('{backspace}');
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@ e2e.scenario({
|
|||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().should('be.visible').click();
|
||||
});
|
||||
|
||||
e2e.components.Select.option().should('be.visible').first().click();
|
||||
e2e.components.Select.option().should('be.visible').first().click();
|
||||
|
||||
e2e.components.FolderPicker.container()
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().should('exist').should('have.focus');
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ describe('Trace view', () => {
|
|||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Select.input().should('be.visible').click();
|
||||
|
||||
e2e().contains('gdev-jaeger').scrollIntoView().should('be.visible').click();
|
||||
});
|
||||
|
||||
e2e().contains('gdev-jaeger').scrollIntoView().should('be.visible').click();
|
||||
|
||||
e2e.components.DataSource.Jaeger.traceIDInput().should('be.visible').type('long-trace');
|
||||
|
||||
e2e.components.RefreshPicker.runButton().should('be.visible').click();
|
||||
|
|
|
|||
|
|
@ -98,15 +98,7 @@ export function createV1Theme(theme: Omit<GrafanaTheme2, 'v1'>): GrafanaTheme {
|
|||
},
|
||||
panelPadding: theme.components.panel.padding * theme.spacing.gridSize,
|
||||
panelHeaderHeight: theme.spacing.gridSize * theme.components.panel.headerHeight,
|
||||
zIndex: {
|
||||
navbarFixed: theme.zIndex.navbarFixed,
|
||||
sidemenu: theme.zIndex.sidemenu,
|
||||
dropdown: theme.zIndex.dropdown,
|
||||
typeahead: theme.zIndex.typeahead,
|
||||
tooltip: theme.zIndex.tooltip,
|
||||
modalBackdrop: theme.zIndex.modalBackdrop,
|
||||
modal: theme.zIndex.modal,
|
||||
},
|
||||
zIndex: theme.zIndex,
|
||||
};
|
||||
|
||||
const basicColors = {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export const zIndex = {
|
|||
tooltip: 1040,
|
||||
modalBackdrop: 1050,
|
||||
modal: 1060,
|
||||
portal: 1061,
|
||||
};
|
||||
|
||||
/** @beta */
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ export interface GrafanaThemeCommons {
|
|||
tooltip: number;
|
||||
modalBackdrop: number;
|
||||
modal: number;
|
||||
portal: number;
|
||||
typeahead: number;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,23 +17,22 @@ export const selectOption = (config: SelectOptionConfig): any => {
|
|||
|
||||
const { clickToOpen, container, forceClickOption, optionText } = fullConfig;
|
||||
|
||||
return container.within(() => {
|
||||
container.within(() => {
|
||||
if (clickToOpen) {
|
||||
e2e().get('[class$="-input-suffix"]').click();
|
||||
}
|
||||
|
||||
e2e.components.Select.option()
|
||||
.filter((_, { textContent }) => {
|
||||
if (textContent === null) {
|
||||
return false;
|
||||
} else if (typeof optionText === 'string') {
|
||||
return textContent.includes(optionText);
|
||||
} else {
|
||||
return optionText.test(textContent);
|
||||
}
|
||||
})
|
||||
.scrollIntoView()
|
||||
.click({ force: forceClickOption });
|
||||
e2e().root().scrollIntoView();
|
||||
});
|
||||
|
||||
return e2e.components.Select.option()
|
||||
.filter((_, { textContent }) => {
|
||||
if (textContent === null) {
|
||||
return false;
|
||||
} else if (typeof optionText === 'string') {
|
||||
return textContent.includes(optionText);
|
||||
} else {
|
||||
return optionText.test(textContent);
|
||||
}
|
||||
})
|
||||
.scrollIntoView()
|
||||
.click({ force: forceClickOption });
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { e2e } from '../index';
|
||||
import { setTimeRange, TimeRangeConfig } from './setTimeRange';
|
||||
|
||||
export { TimeRangeConfig };
|
||||
|
||||
export const setDashboardTimeRange = (config: TimeRangeConfig) =>
|
||||
e2e.components.PageToolbar.container().within(() => setTimeRange(config));
|
||||
export const setDashboardTimeRange = (config: TimeRangeConfig) => setTimeRange(config);
|
||||
|
|
|
|||
|
|
@ -71,6 +71,10 @@ export function Modal(props: PropsWithChildren<Props>) {
|
|||
|
||||
return (
|
||||
<Portal>
|
||||
<div
|
||||
className={styles.modalBackdrop}
|
||||
onClick={onClickBackdrop || (closeOnBackdropClick ? onDismiss : undefined)}
|
||||
/>
|
||||
<div className={cx(styles.modal, className)}>
|
||||
<div className={headerClass}>
|
||||
{typeof title === 'string' && <DefaultModalHeader {...props} title={title} />}
|
||||
|
|
@ -81,10 +85,6 @@ export function Modal(props: PropsWithChildren<Props>) {
|
|||
</div>
|
||||
<div className={cx(styles.modalContent, contentClassName)}>{children}</div>
|
||||
</div>
|
||||
<div
|
||||
className={styles.modalBackdrop}
|
||||
onClick={onClickBackdrop || (closeOnBackdropClick ? onDismiss : undefined)}
|
||||
/>
|
||||
</Portal>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ export const getModalStyles = stylesFactory((theme: GrafanaTheme2) => {
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: ${theme.zIndex.modalBackdrop};
|
||||
background-color: ${theme.components.overlay.background};
|
||||
backdrop-filter: blur(1px);
|
||||
`,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { PureComponent } from 'react';
|
||||
import React, { PropsWithChildren, useEffect, useState } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { useTheme2 } from '../../themes';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
|
|
@ -7,37 +8,29 @@ interface Props {
|
|||
forwardedRef?: any;
|
||||
}
|
||||
|
||||
export class Portal extends PureComponent<Props> {
|
||||
node: HTMLElement = document.createElement('div');
|
||||
portalRoot: HTMLElement;
|
||||
export function Portal(props: PropsWithChildren<Props>) {
|
||||
const { children, className, root = document.body, forwardedRef } = props;
|
||||
const theme = useTheme2();
|
||||
const [node] = useState(document.createElement('div'));
|
||||
const portalRoot = root;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { className, root = document.body } = this.props;
|
||||
|
||||
if (className) {
|
||||
this.node.classList.add(className);
|
||||
}
|
||||
|
||||
this.portalRoot = root;
|
||||
this.portalRoot.appendChild(this.node);
|
||||
if (className) {
|
||||
node.classList.add(className);
|
||||
}
|
||||
node.style.position = 'relative';
|
||||
node.style.zIndex = `${theme.zIndex.portal}`;
|
||||
|
||||
componentWillUnmount() {
|
||||
this.portalRoot.removeChild(this.node);
|
||||
}
|
||||
useEffect(() => {
|
||||
portalRoot.appendChild(node);
|
||||
return () => {
|
||||
portalRoot.removeChild(node);
|
||||
};
|
||||
}, [node, portalRoot]);
|
||||
|
||||
render() {
|
||||
// Default z-index is high to make sure
|
||||
return ReactDOM.createPortal(
|
||||
<div style={{ zIndex: 1051, position: 'relative' }} ref={this.props.forwardedRef}>
|
||||
{this.props.children}
|
||||
</div>,
|
||||
this.node
|
||||
);
|
||||
}
|
||||
return ReactDOM.createPortal(<div ref={forwardedRef}>{children}</div>, node);
|
||||
}
|
||||
|
||||
export const RefForwardingPortal = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
|
||||
return <Portal {...props} forwardedRef={ref} />;
|
||||
});
|
||||
RefForwardingPortal.displayName = 'RefForwardingPortal';
|
||||
|
|
|
|||
|
|
@ -1,44 +1,38 @@
|
|||
import React, { useState } from 'react';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import selectEvent from 'react-select-event';
|
||||
import { SelectBase } from './SelectBase';
|
||||
import { SelectBaseProps } from './types';
|
||||
import { selectOptionInTest } from './test-utils';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { MultiValueContainer } from './MultiValue';
|
||||
|
||||
const onChangeHandler = () => jest.fn();
|
||||
const findMenuElement = (container: ReactWrapper) => container.find({ 'aria-label': 'Select options menu' });
|
||||
const options: Array<SelectableValue<number>> = [
|
||||
{
|
||||
label: 'Option 1',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'Option 2',
|
||||
value: 2,
|
||||
},
|
||||
];
|
||||
import { SelectBase } from './SelectBase';
|
||||
|
||||
describe('SelectBase', () => {
|
||||
const onChangeHandler = () => jest.fn();
|
||||
const options: Array<SelectableValue<number>> = [
|
||||
{
|
||||
label: 'Option 1',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'Option 2',
|
||||
value: 2,
|
||||
},
|
||||
];
|
||||
|
||||
it('renders without error', () => {
|
||||
mount(<SelectBase onChange={onChangeHandler} />);
|
||||
render(<SelectBase onChange={onChangeHandler} />);
|
||||
});
|
||||
|
||||
it('renders empty options information', () => {
|
||||
const container = mount(<SelectBase onChange={onChangeHandler} isOpen />);
|
||||
const noopt = container.find({ 'aria-label': 'No options provided' });
|
||||
expect(noopt).toHaveLength(1);
|
||||
render(<SelectBase onChange={onChangeHandler} />);
|
||||
userEvent.click(screen.getByText(/choose/i));
|
||||
expect(screen.queryByText(/no options found/i)).toBeVisible();
|
||||
});
|
||||
|
||||
it('is selectable via its label text', async () => {
|
||||
const onChange = jest.fn();
|
||||
|
||||
render(
|
||||
<>
|
||||
<label htmlFor="my-select">My select</label>
|
||||
<SelectBase onChange={onChange} options={options} inputId="my-select" />
|
||||
<SelectBase onChange={onChangeHandler} options={options} inputId="my-select" />
|
||||
</>
|
||||
);
|
||||
|
||||
|
|
@ -67,11 +61,9 @@ describe('SelectBase', () => {
|
|||
describe('when openMenuOnFocus prop', () => {
|
||||
describe('is provided', () => {
|
||||
it('opens on focus', () => {
|
||||
const container = mount(<SelectBase onChange={onChangeHandler} openMenuOnFocus />);
|
||||
container.find('input').simulate('focus');
|
||||
|
||||
const menu = findMenuElement(container);
|
||||
expect(menu).toHaveLength(1);
|
||||
render(<SelectBase onChange={onChangeHandler} openMenuOnFocus />);
|
||||
fireEvent.focus(screen.getByRole('textbox'));
|
||||
expect(screen.queryByText(/no options found/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
describe('is not provided', () => {
|
||||
|
|
@ -81,12 +73,10 @@ describe('SelectBase', () => {
|
|||
${'ArrowUp'}
|
||||
${' '}
|
||||
`('opens on arrow down/up or space', ({ key }) => {
|
||||
const container = mount(<SelectBase onChange={onChangeHandler} />);
|
||||
const input = container.find('input');
|
||||
input.simulate('focus');
|
||||
input.simulate('keydown', { key });
|
||||
const menu = findMenuElement(container);
|
||||
expect(menu).toHaveLength(1);
|
||||
render(<SelectBase onChange={onChangeHandler} />);
|
||||
fireEvent.focus(screen.getByRole('textbox'));
|
||||
fireEvent.keyDown(screen.getByRole('textbox'), { key });
|
||||
expect(screen.queryByText(/no options found/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -120,7 +110,7 @@ describe('SelectBase', () => {
|
|||
|
||||
describe('is provided', () => {
|
||||
it('should only display maxVisibleValues options, and additional number of values should be displayed as indicator', () => {
|
||||
const container = mount(
|
||||
render(
|
||||
<SelectBase
|
||||
onChange={onChangeHandler}
|
||||
isMulti={true}
|
||||
|
|
@ -130,14 +120,13 @@ describe('SelectBase', () => {
|
|||
isOpen={false}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(container.find(MultiValueContainer)).toHaveLength(3);
|
||||
expect(container.find('#excess-values').text()).toBe('(+2)');
|
||||
expect(screen.queryAllByText(/option/i).length).toBe(3);
|
||||
expect(screen.queryByText(/\(\+2\)/i)).toBeVisible();
|
||||
});
|
||||
|
||||
describe('and showAllSelectedWhenOpen prop is true', () => {
|
||||
it('should show all selected options when menu is open', () => {
|
||||
const container = mount(
|
||||
render(
|
||||
<SelectBase
|
||||
onChange={onChangeHandler}
|
||||
isMulti={true}
|
||||
|
|
@ -149,14 +138,14 @@ describe('SelectBase', () => {
|
|||
/>
|
||||
);
|
||||
|
||||
expect(container.find(MultiValueContainer)).toHaveLength(5);
|
||||
expect(container.find('#excess-values')).toHaveLength(0);
|
||||
expect(screen.queryAllByText(/option/i).length).toBe(5);
|
||||
expect(screen.queryByText(/\(\+2\)/i)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('and showAllSelectedWhenOpen prop is false', () => {
|
||||
it('should not show all selected options when menu is open', () => {
|
||||
const container = mount(
|
||||
render(
|
||||
<SelectBase
|
||||
onChange={onChangeHandler}
|
||||
isMulti={true}
|
||||
|
|
@ -168,15 +157,15 @@ describe('SelectBase', () => {
|
|||
/>
|
||||
);
|
||||
|
||||
expect(container.find('#excess-values').text()).toBe('(+2)');
|
||||
expect(container.find(MultiValueContainer)).toHaveLength(3);
|
||||
expect(screen.queryAllByText(/option/i).length).toBe(3);
|
||||
expect(screen.queryByText(/\(\+2\)/i)).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('is not provided', () => {
|
||||
it('should always show all selected options', () => {
|
||||
const container = mount(
|
||||
render(
|
||||
<SelectBase
|
||||
onChange={onChangeHandler}
|
||||
isMulti={true}
|
||||
|
|
@ -186,15 +175,16 @@ describe('SelectBase', () => {
|
|||
/>
|
||||
);
|
||||
|
||||
expect(container.find(MultiValueContainer)).toHaveLength(5);
|
||||
expect(container.find('#excess-values')).toHaveLength(0);
|
||||
expect(screen.queryAllByText(/option/i).length).toBe(5);
|
||||
expect(screen.queryByText(/\(\+2\)/i)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('options', () => {
|
||||
it('renders menu with provided options', () => {
|
||||
render(<SelectBase options={options} onChange={onChangeHandler} isOpen />);
|
||||
render(<SelectBase options={options} onChange={onChangeHandler} />);
|
||||
userEvent.click(screen.getByText(/choose/i));
|
||||
const menuOptions = screen.getAllByLabelText('Select option');
|
||||
expect(menuOptions).toHaveLength(2);
|
||||
});
|
||||
|
|
@ -207,60 +197,11 @@ describe('SelectBase', () => {
|
|||
const selectEl = screen.getByLabelText('My select');
|
||||
expect(selectEl).toBeInTheDocument();
|
||||
|
||||
await selectEvent.select(selectEl, 'Option 2');
|
||||
await selectOptionInTest(selectEl, 'Option 2');
|
||||
expect(spy).toHaveBeenCalledWith({
|
||||
label: 'Option 2',
|
||||
value: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When allowCustomValue is set to true', () => {
|
||||
it('Should allow creating a new option', async () => {
|
||||
const valueIsStrictlyEqual: SelectBaseProps<string>['filterOption'] = (option, value) => option.value === value;
|
||||
const valueIsStrictlyNotEqual: SelectBaseProps<string>['isValidNewOption'] = (newOption, _, options) =>
|
||||
options.every(({ value }) => value !== newOption);
|
||||
|
||||
const spy = jest.fn();
|
||||
render(
|
||||
<SelectBase
|
||||
onChange={spy}
|
||||
isOpen
|
||||
allowCustomValue
|
||||
filterOption={valueIsStrictlyEqual}
|
||||
isValidNewOption={valueIsStrictlyNotEqual}
|
||||
/>
|
||||
);
|
||||
|
||||
const textBox = screen.getByRole('textbox');
|
||||
userEvent.type(textBox, 'NOT AN OPTION');
|
||||
|
||||
let creatableOption = screen.getByLabelText('Select option');
|
||||
expect(creatableOption).toBeInTheDocument();
|
||||
expect(creatableOption).toHaveTextContent('Create: NOT AN OPTION');
|
||||
|
||||
userEvent.click(creatableOption);
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
label: 'NOT AN OPTION',
|
||||
value: 'NOT AN OPTION',
|
||||
})
|
||||
);
|
||||
|
||||
// Should also create options in a case-insensitive way.
|
||||
userEvent.type(textBox, 'not an option');
|
||||
|
||||
creatableOption = screen.getByLabelText('Select option');
|
||||
expect(creatableOption).toBeInTheDocument();
|
||||
expect(creatableOption).toHaveTextContent('Create: not an option');
|
||||
|
||||
userEvent.click(creatableOption);
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
label: 'not an option',
|
||||
value: 'not an option',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ export function SelectBase<T>({
|
|||
maxMenuHeight = 300,
|
||||
minMenuHeight,
|
||||
maxVisibleValues,
|
||||
menuPlacement = 'bottom',
|
||||
menuPlacement = 'auto',
|
||||
menuPosition,
|
||||
noOptionsMessage = 'No options found',
|
||||
onBlur,
|
||||
|
|
@ -175,6 +175,10 @@ export function SelectBase<T>({
|
|||
backspaceRemovesValue,
|
||||
captureMenuScroll: false,
|
||||
closeMenuOnSelect,
|
||||
// We don't want to close if we're actually scrolling the menu
|
||||
// So only close if none of the parents are the select menu itself
|
||||
closeMenuOnScroll: (scrollEvent: Event) =>
|
||||
!scrollEvent.composedPath().some((pathItem) => (pathItem as Element).classList?.value.includes(styles.menu)),
|
||||
defaultValue,
|
||||
// Also passing disabled, as this is the new Select API, and I want to use this prop instead of react-select's one
|
||||
disabled,
|
||||
|
|
@ -197,6 +201,7 @@ export function SelectBase<T>({
|
|||
maxVisibleValues,
|
||||
menuIsOpen: isOpen,
|
||||
menuPlacement,
|
||||
menuPortalTarget: document.body,
|
||||
menuPosition,
|
||||
menuShouldScrollIntoView: false,
|
||||
onBlur,
|
||||
|
|
@ -329,19 +334,16 @@ export function SelectBase<T>({
|
|||
}}
|
||||
styles={{
|
||||
...resetSelectStyles(),
|
||||
menuPortal: ({ position, width }: any) => ({
|
||||
position,
|
||||
width,
|
||||
zIndex: theme.zIndex.dropdown,
|
||||
menuPortal: (base: any) => ({
|
||||
...base,
|
||||
zIndex: theme.zIndex.portal,
|
||||
}),
|
||||
//These are required for the menu positioning to function
|
||||
menu: ({ top, bottom, position }: any) => ({
|
||||
top,
|
||||
bottom,
|
||||
position,
|
||||
marginBottom: !!bottom ? '10px' : '0',
|
||||
minWidth: '100%',
|
||||
zIndex: theme.zIndex.dropdown,
|
||||
}),
|
||||
container: () => ({
|
||||
position: 'relative',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
import { select } from 'react-select-event';
|
||||
|
||||
// Used to select an option or options from a Select in unit tests
|
||||
export const selectOptionInTest = async (
|
||||
input: HTMLElement,
|
||||
optionOrOptions: string | RegExp | Array<string | RegExp>
|
||||
) => await select(input, optionOrOptions, { container: document.body });
|
||||
|
|
@ -3,7 +3,7 @@ import { fireEvent, render, screen } from '@testing-library/react';
|
|||
import { ValueMappingsEditorModal, Props } from './ValueMappingsEditorModal';
|
||||
import { MappingType } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import selectEvent from 'react-select-event';
|
||||
import { selectOptionInTest } from '../Select/test-utils';
|
||||
|
||||
const setup = (spy?: any, propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
|
|
@ -79,7 +79,8 @@ describe('When adding and updating value mapp', () => {
|
|||
|
||||
fireEvent.click(screen.getByLabelText(selectors.components.ValuePicker.button('Add a new mapping')));
|
||||
const selectComponent = await screen.findByLabelText(selectors.components.ValuePicker.select('Add a new mapping'));
|
||||
await selectEvent.select(selectComponent, 'Value');
|
||||
|
||||
await selectOptionInTest(selectComponent, 'Value');
|
||||
|
||||
const input = (await screen.findAllByPlaceholderText('Exact value to match'))[1];
|
||||
|
||||
|
|
@ -123,7 +124,7 @@ describe('When adding and updating range map', () => {
|
|||
|
||||
fireEvent.click(screen.getByLabelText(selectors.components.ValuePicker.button('Add a new mapping')));
|
||||
const selectComponent = await screen.findByLabelText(selectors.components.ValuePicker.select('Add a new mapping'));
|
||||
await selectEvent.select(selectComponent, 'Range');
|
||||
await selectOptionInTest(selectComponent, 'Range');
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('Range start'), { target: { value: '10' } });
|
||||
fireEvent.change(screen.getByPlaceholderText('Range end'), { target: { value: '20' } });
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ export { InlineFieldRow } from './Forms/InlineFieldRow';
|
|||
export { FieldArray } from './Forms/FieldArray';
|
||||
|
||||
export { default as resetSelectStyles } from './Select/resetSelectStyles';
|
||||
export { selectOptionInTest } from './Select/test-utils';
|
||||
export * from './Select/Select';
|
||||
|
||||
export { HorizontalGroup, VerticalGroup, Container } from './Layout/Layout';
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ const theme: GrafanaThemeCommons = {
|
|||
tooltip: 1040,
|
||||
modalBackdrop: 1050,
|
||||
modal: 1060,
|
||||
portal: 1061,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { toDataFrame, FieldType } from '@grafana/data';
|
||||
import { fireEvent, render, screen, getByText } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
import { Props, ConfigFromQueryTransformerEditor } from './ConfigFromQueryTransformerEditor';
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -40,7 +40,7 @@ describe('ConfigFromQueryTransformerEditor', () => {
|
|||
|
||||
let select = (await screen.findByText('Config query')).nextSibling!;
|
||||
await fireEvent.keyDown(select, { keyCode: 40 });
|
||||
await userEvent.click(getByText(select as HTMLElement, 'A'));
|
||||
await selectOptionInTest(select as HTMLElement, 'A');
|
||||
|
||||
expect(mockOnChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { toDataFrame, FieldType } from '@grafana/data';
|
||||
import { fireEvent, render, screen, getByText, getByLabelText } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
import { Props, FieldToConfigMappingEditor } from './FieldToConfigMappingEditor';
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -45,7 +46,7 @@ describe('FieldToConfigMappingEditor', () => {
|
|||
|
||||
const select = (await screen.findByTestId('Miiin-config-key')).childNodes[0];
|
||||
await fireEvent.keyDown(select, { keyCode: 40 });
|
||||
await userEvent.click(getByText(select as HTMLElement, 'Min'));
|
||||
await selectOptionInTest(select as HTMLElement, 'Min');
|
||||
|
||||
expect(mockOnChange).toHaveBeenCalledWith(expect.arrayContaining([{ fieldName: 'Miiin', handlerKey: 'min' }]));
|
||||
});
|
||||
|
|
@ -80,7 +81,7 @@ describe('FieldToConfigMappingEditor', () => {
|
|||
const reducer = await (await screen.findByTestId('max-reducer')).childNodes[0];
|
||||
|
||||
await fireEvent.keyDown(reducer, { keyCode: 40 });
|
||||
await userEvent.click(getByText(reducer as HTMLElement, 'Last'));
|
||||
await selectOptionInTest(reducer as HTMLElement, 'Last');
|
||||
|
||||
expect(mockOnChange).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([{ fieldName: 'max', handlerKey: 'max', reducerId: 'last' }])
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { toDataFrame, FieldType } from '@grafana/data';
|
||||
import { fireEvent, render, screen, getByText } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
import { Props, RowsToFieldsTransformerEditor } from './RowsToFieldsTransformerEditor';
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -37,7 +37,7 @@ describe('RowsToFieldsTransformerEditor', () => {
|
|||
|
||||
const select = (await screen.findByTestId('Name-config-key')).childNodes[0];
|
||||
await fireEvent.keyDown(select, { keyCode: 40 });
|
||||
await userEvent.click(getByText(select as HTMLElement, 'Field name'));
|
||||
await selectOptionInTest(select as HTMLElement, 'Field name');
|
||||
|
||||
expect(mockOnChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
|
@ -51,7 +51,7 @@ describe('RowsToFieldsTransformerEditor', () => {
|
|||
|
||||
const select = (await screen.findByTestId('Value-config-key')).childNodes[0];
|
||||
await fireEvent.keyDown(select, { keyCode: 40 });
|
||||
await userEvent.click(getByText(select as HTMLElement, 'Field value'));
|
||||
await selectOptionInTest(select as HTMLElement, 'Field value');
|
||||
|
||||
expect(mockOnChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { mockDataSource, MockDataSourceSrv } from './mocks';
|
|||
import { getAllDataSources } from './utils/config';
|
||||
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
|
|
@ -239,7 +240,7 @@ describe('AmRoutes', () => {
|
|||
|
||||
// configure receiver & group by
|
||||
const receiverSelect = await ui.receiverSelect.find();
|
||||
clickSelectOption(receiverSelect, 'critical');
|
||||
await clickSelectOption(receiverSelect, 'critical');
|
||||
|
||||
const groupSelect = ui.groupSelect.get();
|
||||
await userEvent.type(byRole('textbox').get(groupSelect), 'namespace{enter}');
|
||||
|
|
@ -298,7 +299,7 @@ describe('AmRoutes', () => {
|
|||
|
||||
// configure receiver & group by
|
||||
const receiverSelect = await ui.receiverSelect.find();
|
||||
clickSelectOption(receiverSelect, 'default');
|
||||
await clickSelectOption(receiverSelect, 'default');
|
||||
|
||||
const groupSelect = ui.groupSelect.get();
|
||||
await userEvent.type(byRole('textbox').get(groupSelect), 'severity{enter}');
|
||||
|
|
@ -343,7 +344,7 @@ describe('AmRoutes', () => {
|
|||
|
||||
const clickSelectOption = async (selectElement: HTMLElement, optionText: string): Promise<void> => {
|
||||
userEvent.click(byRole('textbox').get(selectElement));
|
||||
userEvent.click(byText(optionText).get(selectElement));
|
||||
await selectOptionInTest(selectElement, optionText);
|
||||
};
|
||||
|
||||
const updateTiming = async (selectElement: HTMLElement, value: string, timeUnit: string): Promise<void> => {
|
||||
|
|
@ -351,5 +352,5 @@ const updateTiming = async (selectElement: HTMLElement, value: string, timeUnit:
|
|||
expect(inputs).toHaveLength(2);
|
||||
await userEvent.type(inputs[0], value);
|
||||
userEvent.click(inputs[1]);
|
||||
userEvent.click(byText(timeUnit).get(selectElement));
|
||||
await selectOptionInTest(selectElement, timeUnit);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import userEvent from '@testing-library/user-event';
|
|||
import { ALERTMANAGER_NAME_LOCAL_STORAGE_KEY, ALERTMANAGER_NAME_QUERY_KEY } from './utils/constants';
|
||||
import store from 'app/core/store';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
|
||||
jest.mock('./api/alertmanager');
|
||||
jest.mock('./api/grafana');
|
||||
|
|
@ -94,7 +95,7 @@ const ui = {
|
|||
|
||||
const clickSelectOption = async (selectElement: HTMLElement, optionText: string): Promise<void> => {
|
||||
userEvent.click(byRole('textbox').get(selectElement));
|
||||
userEvent.click(byText(optionText).get(selectElement));
|
||||
await selectOptionInTest(selectElement, optionText);
|
||||
};
|
||||
|
||||
describe('Receivers', () => {
|
||||
|
|
@ -166,7 +167,7 @@ describe('Receivers', () => {
|
|||
await ui.inputs.name.find();
|
||||
|
||||
// select hipchat
|
||||
clickSelectOption(byTestId('items.0.type').get(), 'HipChat');
|
||||
await clickSelectOption(byTestId('items.0.type').get(), 'HipChat');
|
||||
|
||||
// check that email options are gone and hipchat options appear
|
||||
expect(ui.inputs.email.addresses.query()).not.toBeInTheDocument();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import RuleEditor from './RuleEditor';
|
|||
import { Router, Route } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
import { byLabelText, byRole, byTestId, byText } from 'testing-library-selector';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { mockDataSource, MockDataSourceSrv } from './mocks';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
|
@ -124,13 +125,13 @@ describe('RuleEditor', () => {
|
|||
|
||||
await renderRuleEditor();
|
||||
await userEvent.type(await ui.inputs.name.find(), 'my great new rule');
|
||||
clickSelectOption(ui.inputs.alertType.get(), /Cortex\/Loki managed alert/);
|
||||
await clickSelectOption(ui.inputs.alertType.get(), /Cortex\/Loki managed alert/);
|
||||
const dataSourceSelect = ui.inputs.dataSource.get();
|
||||
userEvent.click(byRole('textbox').get(dataSourceSelect));
|
||||
userEvent.click(await byText('Prom (default)').find(dataSourceSelect));
|
||||
await clickSelectOption(dataSourceSelect, 'Prom (default)');
|
||||
await waitFor(() => expect(mocks.api.fetchRulerRules).toHaveBeenCalled());
|
||||
clickSelectOption(ui.inputs.namespace.get(), 'namespace2');
|
||||
clickSelectOption(ui.inputs.group.get(), 'group2');
|
||||
await clickSelectOption(ui.inputs.namespace.get(), 'namespace2');
|
||||
await clickSelectOption(ui.inputs.group.get(), 'group2');
|
||||
|
||||
await userEvent.type(ui.inputs.expr.get(), 'up == 1');
|
||||
|
||||
|
|
@ -192,10 +193,10 @@ describe('RuleEditor', () => {
|
|||
// fill out the form
|
||||
await renderRuleEditor();
|
||||
userEvent.type(await ui.inputs.name.find(), 'my great new rule');
|
||||
clickSelectOption(ui.inputs.alertType.get(), /Classic Grafana alerts based on thresholds/);
|
||||
await clickSelectOption(ui.inputs.alertType.get(), /Classic Grafana alerts based on thresholds/);
|
||||
const folderInput = await ui.inputs.folder.find();
|
||||
await waitFor(() => expect(searchFolderMock).toHaveBeenCalled());
|
||||
clickSelectOption(folderInput, 'Folder A');
|
||||
await clickSelectOption(folderInput, 'Folder A');
|
||||
|
||||
await userEvent.type(ui.inputs.annotationValue(0).get(), 'some summary');
|
||||
await userEvent.type(ui.inputs.annotationValue(1).get(), 'some description');
|
||||
|
|
@ -308,7 +309,7 @@ describe('RuleEditor', () => {
|
|||
// render rule editor, select cortex/loki managed alerts
|
||||
await renderRuleEditor();
|
||||
await ui.inputs.name.find();
|
||||
clickSelectOption(ui.inputs.alertType.get(), /Cortex\/Loki managed alert/);
|
||||
await clickSelectOption(ui.inputs.alertType.get(), /Cortex\/Loki managed alert/);
|
||||
|
||||
// wait for ui theck each datasource if it supports rule editing
|
||||
await waitFor(() => expect(mocks.api.fetchRulerRulesGroup).toHaveBeenCalledTimes(4));
|
||||
|
|
@ -316,16 +317,16 @@ describe('RuleEditor', () => {
|
|||
// check that only rules sources that have ruler available are there
|
||||
const dataSourceSelect = ui.inputs.dataSource.get();
|
||||
userEvent.click(byRole('textbox').get(dataSourceSelect));
|
||||
expect(await byText('loki with ruler').find(dataSourceSelect)).toBeInTheDocument();
|
||||
expect(byText('cortex with ruler').query(dataSourceSelect)).toBeInTheDocument();
|
||||
expect(byText('loki with local rule store').query(dataSourceSelect)).not.toBeInTheDocument();
|
||||
expect(byText('prom without ruler api').query(dataSourceSelect)).not.toBeInTheDocument();
|
||||
expect(byText('splunk').query(dataSourceSelect)).not.toBeInTheDocument();
|
||||
expect(byText('loki disabled for alerting').query(dataSourceSelect)).not.toBeInTheDocument();
|
||||
expect(await byText('loki with ruler').query()).toBeInTheDocument();
|
||||
expect(byText('cortex with ruler').query()).toBeInTheDocument();
|
||||
expect(byText('loki with local rule store').query()).not.toBeInTheDocument();
|
||||
expect(byText('prom without ruler api').query()).not.toBeInTheDocument();
|
||||
expect(byText('splunk').query()).not.toBeInTheDocument();
|
||||
expect(byText('loki disabled for alerting').query()).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
const clickSelectOption = (selectElement: HTMLElement, optionText: Matcher): void => {
|
||||
const clickSelectOption = async (selectElement: HTMLElement, optionText: Matcher): Promise<void> => {
|
||||
userEvent.click(byRole('textbox').get(selectElement));
|
||||
userEvent.click(byText(optionText).get(selectElement));
|
||||
await selectOptionInTest(selectElement, optionText as string);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
|
||||
import { byRole, byText } from 'testing-library-selector';
|
||||
import { byRole } from 'testing-library-selector';
|
||||
import { Props, GeneralSettingsUnconnected as GeneralSettings } from './GeneralSettings';
|
||||
import { DashboardModel } from '../../state';
|
||||
|
||||
|
|
@ -45,11 +46,6 @@ const setupTestContext = (options: Partial<Props>) => {
|
|||
return { rerender, props };
|
||||
};
|
||||
|
||||
const clickSelectOption = async (selectElement: HTMLElement, optionText: string): Promise<void> => {
|
||||
userEvent.click(byRole('textbox').get(selectElement));
|
||||
userEvent.click(byText(optionText).get(selectElement));
|
||||
};
|
||||
|
||||
describe('General Settings', () => {
|
||||
describe('when component is mounted with timezone', () => {
|
||||
it('should render correctly', () => {
|
||||
|
|
@ -66,7 +62,9 @@ describe('General Settings', () => {
|
|||
it('should call update function', async () => {
|
||||
const { props } = setupTestContext({});
|
||||
userEvent.click(screen.getByLabelText('Time zone picker select container'));
|
||||
await clickSelectOption(screen.getByLabelText('Time zone picker select container'), 'Browser Time');
|
||||
const timeZonePicker = screen.getByLabelText('Time zone picker select container');
|
||||
userEvent.click(byRole('textbox').get(timeZonePicker));
|
||||
await selectOptionInTest(timeZonePicker, 'Browser Time');
|
||||
expect(props.updateTimeZone).toHaveBeenCalledWith('browser');
|
||||
expect(props.dashboard.timezone).toBe('browser');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { render, fireEvent, screen, waitFor, act } from '@testing-library/react';
|
||||
import selectEvent from 'react-select-event';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
import * as SearchSrv from 'app/core/services/search_srv';
|
||||
import * as MockSearchSrv from 'app/core/services/__mocks__/search_srv';
|
||||
import { DashboardSearch, Props } from './DashboardSearch';
|
||||
|
|
@ -105,7 +105,7 @@ describe('DashboardSearch', () => {
|
|||
await waitFor(() => screen.getByLabelText('Tag filter'));
|
||||
|
||||
const tagComponent = screen.getByLabelText('Tag filter');
|
||||
await selectEvent.select(tagComponent, 'tag1');
|
||||
await selectOptionInTest(tagComponent, 'tag1');
|
||||
|
||||
expect(tagComponent).toBeInTheDocument();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import selectEvent from 'react-select-event';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
import { Props, SearchResultsFilter } from './SearchResultsFilter';
|
||||
import { SearchLayout } from '../types';
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ describe('SearchResultsFilter', () => {
|
|||
query: { ...searchQuery, tag: [] },
|
||||
});
|
||||
const tagComponent = await screen.findByLabelText('Tag filter');
|
||||
await selectEvent.select(tagComponent, 'tag1');
|
||||
await selectOptionInTest(tagComponent, 'tag1');
|
||||
|
||||
expect(mockFilterByTags).toHaveBeenCalledTimes(1);
|
||||
expect(mockFilterByTags).toHaveBeenCalledWith(['tag1']);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import selectEvent from 'react-select-event';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
|
||||
import MetricsQueryEditor from './MetricsQueryEditor';
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ describe('Azure Monitor QueryEditor', () => {
|
|||
);
|
||||
|
||||
const subscriptions = await screen.findByLabelText('Subscription');
|
||||
await selectEvent.select(subscriptions, 'Another Subscription');
|
||||
await selectOptionInTest(subscriptions, 'Another Subscription');
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
...mockQuery,
|
||||
|
|
@ -102,7 +102,7 @@ describe('Azure Monitor QueryEditor', () => {
|
|||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const metrics = await screen.findByLabelText('Metric');
|
||||
await selectEvent.select(metrics, 'Metric B');
|
||||
await selectOptionInTest(metrics, 'Metric B');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
|
|
@ -141,7 +141,7 @@ describe('Azure Monitor QueryEditor', () => {
|
|||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const metrics = await screen.findByLabelText('Metric');
|
||||
await selectEvent.select(metrics, 'Metric B');
|
||||
await selectOptionInTest(metrics, 'Metric B');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
|
|
@ -170,7 +170,7 @@ describe('Azure Monitor QueryEditor', () => {
|
|||
await waitFor(() => expect(screen.getByTestId('azure-monitor-metrics-query-editor')).toBeInTheDocument());
|
||||
|
||||
const aggregation = await screen.findByLabelText('Aggregation');
|
||||
await selectEvent.select(aggregation, 'Maximum');
|
||||
await selectOptionInTest(aggregation, 'Maximum');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith({
|
||||
...mockQuery,
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ describe('Azure Monitor QueryEditor', () => {
|
|||
await waitFor(() => expect(screen.getByTestId('azure-monitor-query-editor')).toBeInTheDocument());
|
||||
|
||||
const metrics = await screen.findByLabelText('Service');
|
||||
await selectEvent.select(metrics, 'Logs');
|
||||
await ui.selectOptionInTest(metrics, 'Logs');
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
...mockQuery,
|
||||
|
|
@ -127,7 +127,7 @@ describe('Azure Monitor QueryEditor', () => {
|
|||
expect(screen.queryByText('Application Insights')).toBeInTheDocument();
|
||||
|
||||
const metrics = await screen.findByLabelText('Service');
|
||||
await selectEvent.select(metrics, 'Logs');
|
||||
await ui.selectOptionInTest(metrics, 'Logs');
|
||||
|
||||
expect(screen.queryByText('Application Insights')).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { select } from 'react-select-event';
|
||||
import { selectOptionInTest } from '@grafana/ui';
|
||||
import { RawInfluxQLEditor } from './RawInfluxQLEditor';
|
||||
import { InfluxQuery } from '../types';
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ describe('RawInfluxQLEditor', () => {
|
|||
const formatSelect = screen.getByLabelText('Format as');
|
||||
expect(formatSelect).toBeInTheDocument();
|
||||
|
||||
await select(formatSelect, 'Time series');
|
||||
await selectOptionInTest(formatSelect, 'Time series');
|
||||
|
||||
expect(onChange).toHaveBeenCalledWith({ ...query, resultFormat: 'time_series' });
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue