Chore: fix some bad uses of userEvent (#82191)

* fix some bad uses of userEvent

* wrap advance call in act

* don't use act

* remove skip

* need act here (see https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning#1-when-using-jestusefaketimers)

* remove test that isn't correct anymore

* implement same change in grafana-prometheus
This commit is contained in:
Ashley Harrison 2024-02-09 10:04:35 +00:00 committed by GitHub
parent e9dab611fe
commit 765a1f8533
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 79 additions and 170 deletions

View File

@ -236,11 +236,10 @@ describe('PromVariableQueryEditor', () => {
await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics');
const metricInput = screen.getByLabelText('Metric selector');
await userEvent.type(metricInput, 'a').then((prom) => {
const queryType = screen.getByLabelText('Query type');
// click elsewhere to trigger the onBlur
return userEvent.click(queryType);
});
await userEvent.type(metricInput, 'a');
const queryType = screen.getByLabelText('Query type');
// click elsewhere to trigger the onBlur
await userEvent.click(queryType);
await waitFor(() =>
expect(onChange).toHaveBeenCalledWith({

View File

@ -38,7 +38,7 @@ describe('PromQail', () => {
it('shows selected metric and asks for a prompt', async () => {
setup(defaultQuery);
clickSecurityButton();
await clickSecurityButton();
await waitFor(() => {
expect(screen.getByText('random_metric')).toBeInTheDocument();
@ -49,7 +49,7 @@ describe('PromQail', () => {
it('displays a prompt when the user knows what they want to query', async () => {
setup(defaultQuery);
clickSecurityButton();
await clickSecurityButton();
await waitFor(() => {
expect(screen.getByText('random_metric')).toBeInTheDocument();
@ -58,7 +58,7 @@ describe('PromQail', () => {
const aiPrompt = screen.getByTestId(queryAssistanttestIds.clickForAi);
userEvent.click(aiPrompt);
await userEvent.click(aiPrompt);
await waitFor(() => {
expect(screen.getByText('What kind of data do you want to see with your metric?')).toBeInTheDocument();
@ -68,7 +68,7 @@ describe('PromQail', () => {
it('does not display a prompt when choosing historical', async () => {
setup(defaultQuery);
clickSecurityButton();
await clickSecurityButton();
await waitFor(() => {
expect(screen.getByText('random_metric')).toBeInTheDocument();
@ -77,7 +77,7 @@ describe('PromQail', () => {
const historicalPrompt = screen.getByTestId(queryAssistanttestIds.clickForHistorical);
userEvent.click(historicalPrompt);
await userEvent.click(historicalPrompt);
await waitFor(() => {
expect(screen.queryByText('What kind of data do you want to see with your metric?')).toBeNull();
@ -141,8 +141,8 @@ function setup(query: PromVisualQuery) {
return container;
}
function clickSecurityButton() {
async function clickSecurityButton() {
const securityInfoButton = screen.getByTestId(queryAssistanttestIds.securityInfoButton);
userEvent.click(securityInfoButton);
await userEvent.click(securityInfoButton);
}

View File

@ -17,7 +17,7 @@ describe('QueryAssistantButton', () => {
const props = createProps(false, 'metric', setShowDrawer);
render(<QueryAssistantButton {...props} />);
const button = screen.getByText('Get query suggestions');
userEvent.hover(button);
await userEvent.hover(button);
await waitFor(() => {
expect(screen.getByText('Install and enable the LLM plugin')).toBeInTheDocument();
});
@ -27,7 +27,7 @@ describe('QueryAssistantButton', () => {
const props = createProps(true, '', setShowDrawer);
render(<QueryAssistantButton {...props} />);
const button = screen.getByText('Get query suggestions');
userEvent.hover(button);
await userEvent.hover(button);
await waitFor(() => {
expect(screen.getByText('First, select a metric.')).toBeInTheDocument();
});

View File

@ -12,12 +12,12 @@ describe('AlertLabels', () => {
render(<AlertLabels labels={labels} commonLabels={commonLabels} />);
expect(screen.getByText('+2 common labels')).toBeInTheDocument();
userEvent.click(screen.getByRole('button'));
await userEvent.click(screen.getByRole('button'));
await waitFor(() => {
expect(screen.getByText('Hide common labels')).toBeInTheDocument();
});
userEvent.click(screen.getByRole('button'));
await userEvent.click(screen.getByRole('button'));
await waitFor(() => {
expect(screen.getByText('+2 common labels')).toBeInTheDocument();
});

View File

@ -1,63 +0,0 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { PluginType } from '@grafana/data';
import { Expression } from './Expression';
const expression =
'100 - ( avg by ( agent_hostname ) ( rate ( node_cpu_seconds_total { mode = "idle" } [ 2h ] ) ) * 100 ) > 97';
const rulesSource = {
id: 5,
uid: 'gdev-prometheus',
type: 'prometheus',
name: 'gdev-prometheus',
meta: {
id: 'prometheus',
type: PluginType.datasource,
name: 'Prometheus',
info: {
author: {
name: 'Grafana Labs',
url: 'https://grafana.com',
},
description: 'Open source time series database & alerting',
links: [
{
name: 'Learn more',
url: 'https://prometheus.io/',
},
],
logos: {
small: 'public/app/plugins/datasource/prometheus/img/prometheus_logo.svg',
large: 'public/app/plugins/datasource/prometheus/img/prometheus_logo.svg',
},
build: {},
screenshots: [],
version: '',
updated: '',
},
module: 'app/plugins/datasource/prometheus/module',
baseUrl: 'public/app/plugins/datasource/prometheus',
},
url: '/api/datasources/proxy/5',
access: 'proxy' as const,
jsonData: {
manageAlerts: true,
},
readOnly: false,
};
describe('Expression', () => {
it('Should not allow to edit the text in the editor', () => {
render(<Expression expression={expression} rulesSource={rulesSource} />);
const editor = screen.getByTestId('expression-editor');
userEvent.type(editor, 'something else');
expect(editor).toHaveTextContent(expression);
expect(editor).not.toHaveTextContent('something else');
});
});

View File

@ -1,4 +1,4 @@
import { act, render, screen } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
@ -60,12 +60,11 @@ describe('PanelDataTransformationsModel', () => {
});
});
describe.skip('PanelDataTransformationsTab', () => {
describe('PanelDataTransformationsTab', () => {
standardTransformersRegistry.setInit(getStandardTransformers);
it('renders empty message when there are no transformations', async () => {
const modelMock = createModelMock({} as PanelData);
userEvent.setup();
render(<PanelDataTransformationsTabRendered model={modelMock}></PanelDataTransformationsTabRendered>);
await screen.findByTestId(selectors.components.Transforms.noTransformationsMessage);
@ -78,7 +77,6 @@ describe.skip('PanelDataTransformationsTab', () => {
options: {},
},
]);
userEvent.setup();
render(<PanelDataTransformationsTabRendered model={modelMock}></PanelDataTransformationsTabRendered>);
await screen.findByText('1 - Add field from calculation');
@ -86,31 +84,23 @@ describe.skip('PanelDataTransformationsTab', () => {
it('shows show the transformation selection drawer', async () => {
const modelMock = createModelMock(mockData);
userEvent.setup();
render(<PanelDataTransformationsTabRendered model={modelMock}></PanelDataTransformationsTabRendered>);
const addButton = await screen.findByTestId(selectors.components.Transforms.addTransformationButton);
await act(async () => {
userEvent.click(addButton);
});
await userEvent.click(addButton);
await screen.findByTestId(selectors.components.Transforms.searchInput);
});
it('adds a transformation when a transformation is clicked in the drawer and there are no previous transformations', async () => {
const onChangeTransformation = jest.fn();
const modelMock = createModelMock(mockData, [], onChangeTransformation);
userEvent.setup();
render(<PanelDataTransformationsTabRendered model={modelMock}></PanelDataTransformationsTabRendered>);
const addButton = await screen.findByTestId(selectors.components.Transforms.addTransformationButton);
await act(async () => {
userEvent.click(addButton);
});
await userEvent.click(addButton);
const transformationCard = await screen.findByTestId(
selectors.components.TransformTab.newTransform('Add field from calculation')
);
const button = transformationCard.getElementsByTagName('button').item(0);
await act(async () => {
await userEvent.click(button!);
});
await userEvent.click(button!);
expect(onChangeTransformation).toHaveBeenCalledWith([{ id: 'calculateField', options: {} }]);
});
@ -127,19 +117,14 @@ describe.skip('PanelDataTransformationsTab', () => {
],
onChangeTransformation
);
userEvent.setup();
render(<PanelDataTransformationsTabRendered model={modelMock}></PanelDataTransformationsTabRendered>);
const addButton = await screen.findByTestId(selectors.components.Transforms.addTransformationButton);
await act(async () => {
userEvent.click(addButton);
});
await userEvent.click(addButton);
const transformationCard = await screen.findByTestId(
selectors.components.TransformTab.newTransform('Add field from calculation')
);
const button = transformationCard.getElementsByTagName('button').item(0);
await act(async () => {
await userEvent.click(button!);
});
await userEvent.click(button!);
expect(onChangeTransformation).toHaveBeenCalledWith([
{ id: 'calculateField', options: {} },
{ id: 'calculateField', options: {} },
@ -158,36 +143,26 @@ describe.skip('PanelDataTransformationsTab', () => {
],
onChangeTransformation
);
userEvent.setup();
render(<PanelDataTransformationsTabRendered model={modelMock}></PanelDataTransformationsTabRendered>);
const removeButton = await screen.findByTestId(selectors.components.Transforms.removeAllTransformationsButton);
await act(async () => {
userEvent.click(removeButton);
});
await userEvent.click(removeButton);
const confirmButton = await screen.findByTestId(selectors.pages.ConfirmModal.delete);
await act(async () => {
await userEvent.click(confirmButton);
});
await userEvent.click(confirmButton);
expect(onChangeTransformation).toHaveBeenCalledWith([]);
});
it('can filter transformations in the drawer', async () => {
const modelMock = createModelMock(mockData);
userEvent.setup();
render(<PanelDataTransformationsTabRendered model={modelMock}></PanelDataTransformationsTabRendered>);
const addButton = await screen.findByTestId(selectors.components.Transforms.addTransformationButton);
await act(async () => {
await userEvent.click(addButton);
});
await userEvent.click(addButton);
const searchInput = await screen.findByTestId(selectors.components.Transforms.searchInput);
await screen.findByTestId(selectors.components.TransformTab.newTransform('Reduce'));
await act(async () => {
await userEvent.type(searchInput, 'add field');
});
await userEvent.type(searchInput, 'add field');
await screen.findByTestId(selectors.components.TransformTab.newTransform('Add field from calculation'));
const reduce = screen.queryByTestId(selectors.components.TransformTab.newTransform('Reduce'));

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { render, screen, waitFor } from '@testing-library/react';
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React, { useState } from 'react';
@ -109,22 +109,26 @@ describe('<NextPrevResult>', () => {
const theme = createTheme();
const tooltip = container.querySelector('.' + getStyles(theme, true).tooltip);
expect(screen.getByText('0 matches')).toBeDefined();
userEvent.hover(tooltip!);
jest.advanceTimersByTime(1000);
await waitFor(() => {
expect(screen.getByText(/0 span matches for the filters selected/)).toBeDefined();
await user.hover(tooltip!);
await act(async () => {
jest.advanceTimersByTime(1000);
});
expect(await screen.findByText(/0 span matches for the filters selected/)).toBeDefined();
});
it('renders services, depth correctly', async () => {
const { container } = render(<NextPrevResultWithProps matches={['264afda25df92413', '364afda25df92413']} />);
const theme = createTheme();
const tooltip = container.querySelector('.' + getStyles(theme, true).tooltip);
userEvent.hover(tooltip!);
jest.advanceTimersByTime(1000);
await waitFor(() => {
expect(screen.getByText(/Services: 2\/3/)).toBeDefined();
expect(screen.getByText(/Depth: 1/)).toBeDefined();
await user.hover(tooltip!);
await act(async () => {
jest.advanceTimersByTime(1000);
});
expect(await screen.findByText(/Services: 2\/3/)).toBeDefined();
expect(await screen.findByText(/Depth: 1/)).toBeDefined();
});
});

View File

@ -83,7 +83,7 @@ describe('QueryEditorRowHeader', () => {
renderScenario({ onChangeDataSource: () => {} });
const dsSelect = screen.getByTestId(selectors.components.DataSourcePicker.container).querySelector('input')!;
userEvent.click(dsSelect);
await userEvent.click(dsSelect);
expect(await screen.findByText('${dsVariable}')).toBeInTheDocument();
});
});

View File

@ -96,12 +96,10 @@ const addFilter = async (
const operationLabel = operation === 'eq' ? '=' : '!=';
const addFilter = await screen.findByLabelText('Add');
await act(() => {
userEvent.click(addFilter);
if (mockQuery.azureTraces?.filters && mockQuery.azureTraces.filters.length < 1) {
expect(onQueryChange).not.toHaveBeenCalled();
}
});
await userEvent.click(addFilter);
if (mockQuery.azureTraces?.filters && mockQuery.azureTraces.filters.length < 1) {
expect(onQueryChange).not.toHaveBeenCalled();
}
await waitFor(() => expect(screen.getByText('Property')).toBeInTheDocument());
const propertySelect = await screen.findByText('Property');
@ -162,8 +160,8 @@ const addFilter = async (
...(mockQuery.azureTraces?.filters ?? []),
{ property, operation, filters: values },
]);
await userEvent.type(valueSelect, '{Escape}');
await waitFor(() => {
userEvent.type(valueSelect, '{Escape}');
expect(onQueryChange).toHaveBeenCalledWith(newQuery);
});

View File

@ -64,11 +64,11 @@ describe('SelectedLogsGroups', () => {
name: `logGroup${i}`,
}));
render(<SelectedLogGroups {...defaultProps} selectedLogGroups={selectedLogGroups} />);
await waitFor(() => userEvent.click(screen.getByText('Clear selection')));
await userEvent.click(screen.getByText('Clear selection'));
await waitFor(() =>
expect(screen.getByText('Are you sure you want to clear all log groups?')).toBeInTheDocument()
);
await waitFor(() => userEvent.click(screen.getByRole('button', { name: 'Yes' })));
await userEvent.click(screen.getByRole('button', { name: 'Yes' }));
expect(defaultProps.onChange).toHaveBeenCalledWith([]);
});
});

View File

@ -116,9 +116,7 @@ describe('Metric Editor', () => {
render(<MetricEditor value={count} />, { wrapper });
act(() => {
userEvent.click(screen.getByText('Count'));
});
await userEvent.click(screen.getByText('Count'));
// we check if the list-of-options is visible by
// checking for an item to exist

View File

@ -36,20 +36,19 @@ describe('DerivedFields', () => {
render(<DerivedFields onChange={onChange} />);
const addButton = await screen.findByText('Add');
userEvent.click(addButton);
await userEvent.click(addButton);
await waitFor(() => expect(onChange).toHaveBeenCalledTimes(1));
});
// TODO: I saw this test being flaky lately, so I commented it out for now
// it('removes a field', async () => {
// const onChange = jest.fn();
// render(<DerivedFields fields={testFields} onChange={onChange} />);
it('removes a field', async () => {
const onChange = jest.fn();
render(<DerivedFields fields={testFields} onChange={onChange} />);
// userEvent.click((await screen.findAllByTitle('Remove field'))[0]);
await userEvent.click((await screen.findAllByTitle('Remove field'))[0]);
// await waitFor(() => expect(onChange).toHaveBeenCalledWith([testFields[1]]));
// });
await waitFor(() => expect(onChange).toHaveBeenCalledWith([testFields[1]]));
});
it('validates duplicated field names', async () => {
const repeatedFields = [
@ -65,7 +64,7 @@ describe('DerivedFields', () => {
render(<DerivedFields onChange={jest.fn()} fields={repeatedFields} />);
const inputs = await screen.findAllByPlaceholderText('Field name');
userEvent.click(inputs[0]);
await userEvent.click(inputs[0]);
expect(await screen.findAllByText('The name is already in use')).toHaveLength(2);
});
@ -84,7 +83,7 @@ describe('DerivedFields', () => {
render(<DerivedFields onChange={jest.fn()} fields={repeatedFields} />);
const inputs = await screen.findAllByPlaceholderText('Field name');
userEvent.click(inputs[0]);
await userEvent.click(inputs[0]);
expect(screen.queryByText('The name is already in use')).not.toBeInTheDocument();
});

View File

@ -50,16 +50,16 @@ describe('LokiQueryBuilderContainer', () => {
const labels = screen.getByText(/Label filters/);
const selects = await findAllByRole(getSelectParent(labels)!, 'combobox');
await userEvent.click(selects[3]);
userEvent.click(await screen.findByText('job'));
await userEvent.click(await screen.findByText('job'));
await userEvent.click(selects[4]);
userEvent.click(await screen.findByText('=~'));
await userEvent.click(await screen.findByText('=~'));
await userEvent.click(selects[5]);
userEvent.click(await screen.findByText('grafana'));
await userEvent.click(await screen.findByText('grafana'));
await userEvent.click(selects[5]);
userEvent.click(await screen.findByText('loki'));
await userEvent.click(await screen.findByText('loki'));
await waitFor(() => {
expect(props.onChange).toBeCalledWith({ expr: '{app="app1", job=~"grafana|loki"}', refId: 'A' });

View File

@ -1,4 +1,4 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
@ -71,7 +71,7 @@ describe('exit the nested query', () => {
it('onRemove is called when clicking (x)', async () => {
const props = createMockProps();
render(<NestedQuery {...props} />);
fireEvent.click(await screen.findByLabelText('Remove nested query'));
await userEvent.click(await screen.findByLabelText('Remove nested query'));
await waitFor(() => expect(props.onRemove).toHaveBeenCalledTimes(1));
});
});
@ -80,8 +80,8 @@ describe('change operator', () => {
it('onChange is called with the correct args', async () => {
const props = createMockProps('/', 'on');
render(<NestedQuery {...props} />);
userEvent.click(await screen.findByLabelText('Select operator'));
fireEvent.click(await screen.findByText('+'));
await userEvent.click(await screen.findByLabelText('Select operator'));
await userEvent.click(await screen.findByText('+'));
await waitFor(() => expect(props.onChange).toHaveBeenCalledTimes(1));
await waitFor(() =>
expect(props.onChange).toHaveBeenCalledWith(0, {

View File

@ -236,11 +236,10 @@ describe('PromVariableQueryEditor', () => {
await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics');
const metricInput = screen.getByLabelText('Metric selector');
await userEvent.type(metricInput, 'a').then((prom) => {
const queryType = screen.getByLabelText('Query type');
// click elsewhere to trigger the onBlur
return userEvent.click(queryType);
});
await userEvent.type(metricInput, 'a');
const queryType = screen.getByLabelText('Query type');
// click elsewhere to trigger the onBlur
await userEvent.click(queryType);
await waitFor(() =>
expect(onChange).toHaveBeenCalledWith({

View File

@ -38,7 +38,7 @@ describe('PromQail', () => {
it('shows selected metric and asks for a prompt', async () => {
setup(defaultQuery);
clickSecurityButton();
await clickSecurityButton();
await waitFor(() => {
expect(screen.getByText('random_metric')).toBeInTheDocument();
@ -49,7 +49,7 @@ describe('PromQail', () => {
it('displays a prompt when the user knows what they want to query', async () => {
setup(defaultQuery);
clickSecurityButton();
await clickSecurityButton();
await waitFor(() => {
expect(screen.getByText('random_metric')).toBeInTheDocument();
@ -58,7 +58,7 @@ describe('PromQail', () => {
const aiPrompt = screen.getByTestId(testIds.clickForAi);
userEvent.click(aiPrompt);
await userEvent.click(aiPrompt);
await waitFor(() => {
expect(screen.getByText('What kind of data do you want to see with your metric?')).toBeInTheDocument();
@ -68,7 +68,7 @@ describe('PromQail', () => {
it('does not display a prompt when choosing historical', async () => {
setup(defaultQuery);
clickSecurityButton();
await clickSecurityButton();
await waitFor(() => {
expect(screen.getByText('random_metric')).toBeInTheDocument();
@ -77,7 +77,7 @@ describe('PromQail', () => {
const historicalPrompt = screen.getByTestId(testIds.clickForHistorical);
userEvent.click(historicalPrompt);
await userEvent.click(historicalPrompt);
await waitFor(() => {
expect(screen.queryByText('What kind of data do you want to see with your metric?')).toBeNull();
@ -141,8 +141,8 @@ function setup(query: PromVisualQuery) {
return container;
}
function clickSecurityButton() {
async function clickSecurityButton() {
const securityInfoButton = screen.getByTestId(testIds.securityInfoButton);
userEvent.click(securityInfoButton);
await userEvent.click(securityInfoButton);
}

View File

@ -17,7 +17,7 @@ describe('QueryAssistantButton', () => {
const props = createProps(false, 'metric', setShowDrawer);
render(<QueryAssistantButton {...props} />);
const button = screen.getByText('Get query suggestions');
userEvent.hover(button);
await userEvent.hover(button);
await waitFor(() => {
expect(screen.getByText('Install and enable the LLM plugin')).toBeInTheDocument();
});
@ -27,7 +27,7 @@ describe('QueryAssistantButton', () => {
const props = createProps(true, '', setShowDrawer);
render(<QueryAssistantButton {...props} />);
const button = screen.getByText('Get query suggestions');
userEvent.hover(button);
await userEvent.hover(button);
await waitFor(() => {
expect(screen.getByText('First, select a metric.')).toBeInTheDocument();
});