From e0e6165f709d0bf2c20744df087ed378190b2724 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Wed, 15 Mar 2023 10:12:13 +0000 Subject: [PATCH] Chore: adjust more unit tests to work with react 18 (#64759) adjust unit tests to work with react 18 --- .betterer.results | 5 - .../src/components/Table/Table.test.tsx | 4 +- .../SharedPreferences.test.tsx | 6 +- .../unified/NotificationPolicies.test.tsx | 3 +- .../unified/RuleEditorExisting.test.tsx | 6 +- .../correlations/CorrelationsPage.test.tsx | 129 ++++++++---------- .../app/features/explore/ExplorePage.test.tsx | 23 ++-- .../app/features/explore/spec/query.test.tsx | 14 +- .../admin/pages/PluginDetails.test.tsx | 14 +- .../query/components/QueryGroup.test.tsx | 37 +++-- .../LogsQueryEditor/LogsQueryEditor.test.tsx | 26 ++-- .../ResourcePicker/ResourcePicker.test.tsx | 43 +++--- .../VariableEditor/VariableEditor.test.tsx | 6 +- .../VisualMetricQueryEditor.test.tsx | 56 ++++---- .../components/QueryEditor.test.tsx | 104 ++++++-------- .../loki/components/LokiQueryEditor.test.tsx | 14 +- .../LokiQueryBuilderContainer.test.tsx | 6 +- .../shared/OperationList.testUtils.ts | 10 +- .../components/FlameGraphContainer.test.tsx | 15 +- 19 files changed, 256 insertions(+), 265 deletions(-) diff --git a/.betterer.results b/.betterer.results index e537a2024aa..d10ae63961d 100644 --- a/.betterer.results +++ b/.betterer.results @@ -4560,11 +4560,6 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], - "public/app/plugins/datasource/cloudwatch/components/QueryEditor.test.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] - ], "public/app/plugins/datasource/cloudwatch/datasource.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], diff --git a/packages/grafana-ui/src/components/Table/Table.test.tsx b/packages/grafana-ui/src/components/Table/Table.test.tsx index 1ecdcdb6bcd..6e13298bb18 100644 --- a/packages/grafana-ui/src/components/Table/Table.test.tsx +++ b/packages/grafana-ui/src/components/Table/Table.test.tsx @@ -548,7 +548,7 @@ describe('Table', () => { }); describe('when mounted with data and sub-data', () => { - it('then correct rows should be rendered and new table is rendered when expander is clicked', () => { + it('then correct rows should be rendered and new table is rendered when expander is clicked', async () => { getTestContext({ subData: new Array(getDefaultDataFrame().length).fill(0).map((i) => toDataFrame({ @@ -588,7 +588,7 @@ describe('Table', () => { { time: '2021-01-01 02:00:00', temperature: '12', link: '12' }, ]); - within(rows[1]).getByLabelText('Expand row').click(); + await userEvent.click(within(rows[1]).getByLabelText('Expand row')); const rowsAfterClick = within(getTable()).getAllByRole('row'); expect(within(rowsAfterClick[1]).getByRole('table')).toBeInTheDocument(); expect(within(rowsAfterClick[1]).getByText(/number0/)).toBeInTheDocument(); diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx index 90bfeb72397..f76896edbfe 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx @@ -133,9 +133,11 @@ describe('SharedPreferences', () => { expect(lightThemeRadio.checked).toBeTruthy(); }); - it('renders the home dashboard preference', () => { + it('renders the home dashboard preference', async () => { const dashboardSelect = getSelectParent(screen.getByLabelText('Home Dashboard')); - expect(dashboardSelect).toHaveTextContent('My Dashboard'); + await waitFor(() => { + expect(dashboardSelect).toHaveTextContent('My Dashboard'); + }); }); it('renders the timezone preference', () => { diff --git a/public/app/features/alerting/unified/NotificationPolicies.test.tsx b/public/app/features/alerting/unified/NotificationPolicies.test.tsx index 3bcbb9825c3..3698e5abc9d 100644 --- a/public/app/features/alerting/unified/NotificationPolicies.test.tsx +++ b/public/app/features/alerting/unified/NotificationPolicies.test.tsx @@ -379,7 +379,7 @@ describe('NotificationPolicies', () => { }); }); - it('hides create and edit button if user does not have permission', () => { + it('hides create and edit button if user does not have permission', async () => { mocks.contextSrv.hasAccess.mockImplementation((action) => [AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingNotificationsRead].includes( action as AccessControlAction @@ -387,6 +387,7 @@ describe('NotificationPolicies', () => { ); renderNotificationPolicies(); + await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalledTimes(1)); expect(ui.newPolicyButton.query()).not.toBeInTheDocument(); expect(ui.editButton.query()).not.toBeInTheDocument(); }); diff --git a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx index ebb6b894b44..44e96fd3dd0 100644 --- a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx @@ -1,4 +1,4 @@ -import { render, waitFor, screen, within } from '@testing-library/react'; +import { render, waitFor, screen, within, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { Route } from 'react-router-dom'; @@ -185,7 +185,9 @@ describe('RuleEditor grafana managed rules', () => { //check that '+ Add new' option is in folders drop down even if we don't have values const emptyFolderInput = await ui.inputs.folderContainer.find(); mocks.searchFolders.mockResolvedValue([] as DashboardSearchHit[]); - await renderRuleEditor(uid); + await act(async () => { + renderRuleEditor(uid); + }); await userEvent.click(within(emptyFolderInput).getByRole('combobox')); expect(screen.getByText(ADD_NEW_FOLER_OPTION)).toBeInTheDocument(); diff --git a/public/app/features/correlations/CorrelationsPage.test.tsx b/public/app/features/correlations/CorrelationsPage.test.tsx index 31d18864ec4..eab9c5ae7e2 100644 --- a/public/app/features/correlations/CorrelationsPage.test.tsx +++ b/public/app/features/correlations/CorrelationsPage.test.tsx @@ -1,13 +1,5 @@ -import { - render, - waitFor, - screen, - fireEvent, - waitForElementToBeRemoved, - within, - Matcher, - getByRole, -} from '@testing-library/react'; +import { render, waitFor, screen, fireEvent, within, Matcher, getByRole } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { merge, uniqueId } from 'lodash'; import React from 'react'; import { DeepPartial } from 'react-hook-form'; @@ -280,6 +272,9 @@ describe('CorrelationsPage', () => { }); it('shows CTA', async () => { + const CTAButton = await screen.findByRole('button', { name: /add correlation/i }); + expect(CTAButton).toBeInTheDocument(); + // insert form should not be present expect(screen.queryByRole('button', { name: /add$/i })).not.toBeInTheDocument(); @@ -289,51 +284,43 @@ describe('CorrelationsPage', () => { // there's no table in the page expect(screen.queryByRole('table')).not.toBeInTheDocument(); - const CTAButton = screen.getByRole('button', { name: /add correlation/i }); - expect(CTAButton).toBeInTheDocument(); - - fireEvent.click(CTAButton); - - // wait for the form to be rendered and query editor to be mounted - await waitForElementToBeRemoved(() => screen.queryByText(/loading query editor/i)); + await userEvent.click(CTAButton); // form's submit button - expect(screen.getByRole('button', { name: /add$/i })).toBeInTheDocument(); + expect(await screen.findByRole('button', { name: /add$/i })).toBeInTheDocument(); }); it('correctly adds first correlation', async () => { - const CTAButton = screen.getByRole('button', { name: /add correlation/i }); + const CTAButton = await screen.findByRole('button', { name: /add correlation/i }); expect(CTAButton).toBeInTheDocument(); // there's no table in the page, as we are adding the first correlation expect(screen.queryByRole('table')).not.toBeInTheDocument(); - fireEvent.click(CTAButton); + await userEvent.click(CTAButton); - fireEvent.change(screen.getByRole('textbox', { name: /label/i }), { target: { value: 'A Label' } }); - fireEvent.change(screen.getByRole('textbox', { name: /description/i }), { target: { value: 'A Description' } }); + await userEvent.clear(screen.getByRole('textbox', { name: /label/i })); + await userEvent.type(screen.getByRole('textbox', { name: /label/i }), 'A Label'); + await userEvent.clear(screen.getByRole('textbox', { name: /description/i })); + await userEvent.type(screen.getByRole('textbox', { name: /description/i }), 'A Description'); // set source datasource picker value fireEvent.keyDown(screen.getByLabelText(/^source$/i), { keyCode: 40 }); - fireEvent.click(screen.getByText('loki')); + await userEvent.click(screen.getByText('loki')); // set target datasource picker value fireEvent.keyDown(screen.getByLabelText(/^target$/i), { keyCode: 40 }); - fireEvent.click(screen.getByText('prometheus')); + await userEvent.click(screen.getByText('prometheus')); - fireEvent.change(screen.getByRole('textbox', { name: /target field/i }), { target: { value: 'Line' } }); + await userEvent.clear(screen.getByRole('textbox', { name: /target field/i })); + await userEvent.type(screen.getByRole('textbox', { name: /target field/i }), 'Line'); - await waitForElementToBeRemoved(() => screen.queryByText(/loading query editor/i)); - - fireEvent.click(screen.getByRole('button', { name: /add$/i })); - - // Waits for the form to be removed, meaning the correlation got successfully saved - await waitForElementToBeRemoved(() => screen.queryByRole('button', { name: /add$/i })); + await userEvent.click(await screen.findByRole('button', { name: /add$/i })); expect(mocks.reportInteraction).toHaveBeenLastCalledWith('grafana_correlations_added'); // the table showing correlations should have appeared - expect(screen.getByRole('table')).toBeInTheDocument(); + expect(await screen.findByRole('table')).toBeInTheDocument(); }); }); @@ -413,12 +400,15 @@ describe('CorrelationsPage', () => { }); it('shows a table with correlations', async () => { - expect(screen.getByRole('table')).toBeInTheDocument(); + expect(await screen.findByRole('table')).toBeInTheDocument(); }); it('correctly sorts by source', async () => { + // wait for table to appear + await screen.findByRole('table'); + const sourceHeader = getByRole(getHeaderByName('Source'), 'button'); - fireEvent.click(sourceHeader); + await userEvent.click(sourceHeader); let cells = queryCellsByColumnName('Source'); cells.forEach((cell, i, allCells) => { const prevCell = allCells[i - 1]; @@ -427,7 +417,7 @@ describe('CorrelationsPage', () => { } }); - fireEvent.click(sourceHeader); + await userEvent.click(sourceHeader); cells = queryCellsByColumnName('Source'); cells.forEach((cell, i, allCells) => { const prevCell = allCells[i - 1]; @@ -438,46 +428,47 @@ describe('CorrelationsPage', () => { }); it('correctly adds new correlation', async () => { - const addNewButton = screen.getByRole('button', { name: /add new/i }); + const addNewButton = await screen.findByRole('button', { name: /add new/i }); expect(addNewButton).toBeInTheDocument(); - fireEvent.click(addNewButton); + await userEvent.click(addNewButton); - fireEvent.change(screen.getByRole('textbox', { name: /label/i }), { target: { value: 'A Label' } }); - fireEvent.change(screen.getByRole('textbox', { name: /description/i }), { target: { value: 'A Description' } }); + await userEvent.clear(screen.getByRole('textbox', { name: /label/i })); + await userEvent.type(screen.getByRole('textbox', { name: /label/i }), 'A Label'); + await userEvent.clear(screen.getByRole('textbox', { name: /description/i })); + await userEvent.type(screen.getByRole('textbox', { name: /description/i }), 'A Description'); // set source datasource picker value fireEvent.keyDown(screen.getByLabelText(/^source$/i), { keyCode: 40 }); - fireEvent.click(within(screen.getByLabelText('Select options menu')).getByText('prometheus')); + await userEvent.click(within(screen.getByLabelText('Select options menu')).getByText('prometheus')); // set target datasource picker value fireEvent.keyDown(screen.getByLabelText(/^target$/i), { keyCode: 40 }); - fireEvent.click(screen.getByText('elastic')); + await userEvent.click(screen.getByText('elastic')); - fireEvent.change(screen.getByRole('textbox', { name: /target field/i }), { target: { value: 'Line' } }); + await userEvent.clear(screen.getByRole('textbox', { name: /target field/i })); + await userEvent.type(screen.getByRole('textbox', { name: /target field/i }), 'Line'); - await waitForElementToBeRemoved(() => screen.queryByText(/loading query editor/i)); - - fireEvent.click(screen.getByRole('button', { name: /add$/i })); - - // the form should get removed after successful submissions - await waitForElementToBeRemoved(() => screen.queryByRole('button', { name: /add$/i })); + await userEvent.click(screen.getByRole('button', { name: /add$/i })); expect(mocks.reportInteraction).toHaveBeenLastCalledWith('grafana_correlations_added'); + + // the table showing correlations should have appeared + expect(await screen.findByRole('table')).toBeInTheDocument(); }); it('correctly closes the form when clicking on the close icon', async () => { - const addNewButton = screen.getByRole('button', { name: /add new/i }); + const addNewButton = await screen.findByRole('button', { name: /add new/i }); expect(addNewButton).toBeInTheDocument(); - fireEvent.click(addNewButton); + await userEvent.click(addNewButton); - fireEvent.click(screen.getByRole('button', { name: /close$/i })); + await userEvent.click(screen.getByRole('button', { name: /close$/i })); expect(screen.queryByRole('button', { name: /add$/i })).not.toBeInTheDocument(); }); it('correctly deletes correlations', async () => { // A row with the correlation should exist - expect(screen.getByRole('cell', { name: /some label/i })).toBeInTheDocument(); + expect(await screen.findByRole('cell', { name: /some label/i })).toBeInTheDocument(); const tableRows = queryRowsByCellValue('Source', 'loki'); @@ -485,36 +476,37 @@ describe('CorrelationsPage', () => { expect(deleteButton).toBeInTheDocument(); - fireEvent.click(deleteButton); + await userEvent.click(deleteButton); const confirmButton = within(tableRows[0]).getByRole('button', { name: /delete$/i }); expect(confirmButton).toBeInTheDocument(); - fireEvent.click(confirmButton); + await userEvent.click(confirmButton); - await waitForElementToBeRemoved(() => screen.queryByRole('cell', { name: /some label$/i })); + expect(screen.queryByRole('cell', { name: /some label$/i })).not.toBeInTheDocument(); expect(mocks.reportInteraction).toHaveBeenLastCalledWith('grafana_correlations_deleted'); }); it('correctly edits correlations', async () => { + // wait for table to appear + await screen.findByRole('table'); + const tableRows = queryRowsByCellValue('Source', 'loki'); const rowExpanderButton = within(tableRows[0]).getByRole('button', { name: /toggle row expanded/i }); - fireEvent.click(rowExpanderButton); + await userEvent.click(rowExpanderButton); expect(mocks.reportInteraction).toHaveBeenLastCalledWith('grafana_correlations_details_expanded'); - await waitForElementToBeRemoved(() => screen.queryByText(/loading query editor/i)); - - fireEvent.change(screen.getByRole('textbox', { name: /label/i }), { target: { value: 'edited label' } }); - fireEvent.change(screen.getByRole('textbox', { name: /description/i }), { - target: { value: 'edited description' }, - }); + await userEvent.clear(screen.getByRole('textbox', { name: /label/i })); + await userEvent.type(screen.getByRole('textbox', { name: /label/i }), 'edited label'); + await userEvent.clear(screen.getByRole('textbox', { name: /description/i })); + await userEvent.type(screen.getByRole('textbox', { name: /description/i }), 'edited description'); expect(screen.queryByRole('cell', { name: /edited label$/i })).not.toBeInTheDocument(); - fireEvent.click(screen.getByRole('button', { name: /save$/i })); + await userEvent.click(screen.getByRole('button', { name: /save$/i })); await waitFor(() => { expect(screen.queryByRole('cell', { name: /edited label$/i })).toBeInTheDocument(); @@ -554,24 +546,21 @@ describe('CorrelationsPage', () => { it("doesn't render delete button", async () => { // A row with the correlation should exist - expect(screen.getByRole('cell', { name: /some label/i })).toBeInTheDocument(); + expect(await screen.findByRole('cell', { name: /some label/i })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: /delete correlation/i })).not.toBeInTheDocument(); }); it('edit form is read only', async () => { // A row with the correlation should exist - const rowExpanderButton = screen.getByRole('button', { name: /toggle row expanded/i }); + const rowExpanderButton = await screen.findByRole('button', { name: /toggle row expanded/i }); - fireEvent.click(rowExpanderButton); + await userEvent.click(rowExpanderButton); expect(mocks.reportInteraction).toHaveBeenLastCalledWith('grafana_correlations_details_expanded'); - // wait for the form to be rendered and query editor to be mounted - await waitForElementToBeRemoved(() => screen.queryByText(/loading query editor/i)); - // form elements should be readonly - const labelInput = screen.getByRole('textbox', { name: /label/i }); + const labelInput = await screen.findByRole('textbox', { name: /label/i }); expect(labelInput).toBeInTheDocument(); expect(labelInput).toHaveAttribute('readonly'); diff --git a/public/app/features/explore/ExplorePage.test.tsx b/public/app/features/explore/ExplorePage.test.tsx index 79fb6bcf86c..0a8e0746af3 100644 --- a/public/app/features/explore/ExplorePage.test.tsx +++ b/public/app/features/explore/ExplorePage.test.tsx @@ -1,4 +1,4 @@ -import { fireEvent, screen, waitFor } from '@testing-library/react'; +import { act, fireEvent, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React, { ComponentProps } from 'react'; import AutoSizer from 'react-virtualized-auto-sizer'; @@ -43,7 +43,7 @@ describe('ExplorePage', () => { setupExplore(); // Wait for rendering the editor const splitButton = await screen.findByText(/split/i); - fireEvent.click(splitButton); + await userEvent.click(splitButton); await waitFor(() => { const editors = screen.getAllByText('loki Editor input:'); expect(editors.length).toBe(2); @@ -123,9 +123,11 @@ describe('ExplorePage', () => { jest.mocked(datasources.loki.query).mockReturnValue(makeLogsQueryResponse()); jest.mocked(datasources.elastic.query).mockReturnValue(makeLogsQueryResponse()); - locationService.partial({ - left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]), - right: JSON.stringify(['now-1h', 'now', 'elastic', { expr: 'error' }]), + act(() => { + locationService.partial({ + left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="value"}' }]), + right: JSON.stringify(['now-1h', 'now', 'elastic', { expr: 'error' }]), + }); }); // Editor renders the new query @@ -145,7 +147,9 @@ describe('ExplorePage', () => { // to work await screen.findByText(`loki Editor input: { label="value"}`); - store.dispatch(mainState.splitOpen({ datasourceUid: 'elastic', query: { expr: 'error', refId: 'A' } })); + act(() => { + store.dispatch(mainState.splitOpen({ datasourceUid: 'elastic', query: { expr: 'error', refId: 'A' } })); + }); // Editor renders the new query await screen.findByText(`elastic Editor input: error`); @@ -155,7 +159,7 @@ describe('ExplorePage', () => { it('handles split size events and sets relevant variables', async () => { setupExplore(); const splitButton = await screen.findByText(/split/i); - fireEvent.click(splitButton); + await userEvent.click(splitButton); await waitForExplore(undefined, true); let widenButton = await screen.findAllByLabelText('Widen pane'); let narrowButton = await screen.queryAllByLabelText('Narrow pane'); @@ -202,7 +206,9 @@ describe('ExplorePage', () => { // to work await screen.findByText(`loki Editor input: { label="value"}`); - store.dispatch(mainState.splitOpen({ datasourceUid: 'elastic', query: { expr: 'error', refId: 'A' } })); + act(() => { + store.dispatch(mainState.splitOpen({ datasourceUid: 'elastic', query: { expr: 'error', refId: 'A' } })); + }); await waitFor(() => expect(document.title).toEqual('Explore - loki | elastic - Grafana')); }); }); @@ -404,6 +410,7 @@ describe('ExplorePage', () => { it('removes `from` and `to` parameters from url when first mounted', async () => { setupExplore({ searchParams: 'from=1&to=2&orgId=1' }); + await waitForExplore(); expect(locationService.getSearchObject()).toEqual(expect.not.objectContaining({ from: '1', to: '2' })); expect(locationService.getSearchObject()).toEqual(expect.objectContaining({ orgId: '1' })); diff --git a/public/app/features/explore/spec/query.test.tsx b/public/app/features/explore/spec/query.test.tsx index 16dea667f66..0a8a8dcaa8d 100644 --- a/public/app/features/explore/spec/query.test.tsx +++ b/public/app/features/explore/spec/query.test.tsx @@ -1,4 +1,4 @@ -import { screen } from '@testing-library/react'; +import { act, screen } from '@testing-library/react'; import { serializeStateToUrlParam } from '@grafana/data'; import { locationService } from '@grafana/runtime'; @@ -70,8 +70,10 @@ describe('Explore: handle running/not running query', () => { jest.mocked(datasources.loki.query).mockReturnValueOnce(makeLogsQueryResponse('different log')); - locationService.partial({ - left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="different"}' }]), + act(() => { + locationService.partial({ + left: JSON.stringify(['now-1h', 'now', 'loki', { expr: '{ label="different"}' }]), + }); }); // Editor renders the new query @@ -89,8 +91,10 @@ describe('Explore: handle running/not running query', () => { jest.mocked(datasources.elastic.query).mockReturnValueOnce(makeMetricsQueryResponse()); - locationService.partial({ - left: JSON.stringify(['now-1h', 'now', 'elastic', { expr: 'other query' }]), + act(() => { + locationService.partial({ + left: JSON.stringify(['now-1h', 'now', 'elastic', { expr: 'other query' }]), + }); }); // Editor renders the new query diff --git a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx index 139a38c9ad9..24f2fdde934 100644 --- a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx +++ b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx @@ -465,17 +465,17 @@ describe('Plugin details page', () => { // Does not show an Install button rendered = renderPluginDetails({ id }, { pluginsStateOverride }); - expect(await rendered.queryByRole('button', { name: /(un)?install/i })).not.toBeInTheDocument(); + expect(rendered.queryByRole('button', { name: /(un)?install/i })).not.toBeInTheDocument(); rendered.unmount(); // Does not show a Uninstall button rendered = renderPluginDetails({ id, isInstalled: true }, { pluginsStateOverride }); - expect(await rendered.queryByRole('button', { name: /(un)?install/i })).not.toBeInTheDocument(); + expect(rendered.queryByRole('button', { name: /(un)?install/i })).not.toBeInTheDocument(); rendered.unmount(); // Does not show an Update button rendered = renderPluginDetails({ id, isInstalled: true, hasUpdate: true }, { pluginsStateOverride }); - expect(await rendered.queryByRole('button', { name: /update/i })).not.toBeInTheDocument(); + expect(rendered.queryByRole('button', { name: /update/i })).not.toBeInTheDocument(); // Shows a message to the user // TODO @@ -491,15 +491,17 @@ describe('Plugin details page', () => { // Should not show an "Install" button rendered = renderPluginDetails({ id, isInstalled: false }); - expect(await rendered.queryByRole('button', { name: /^install/i })).not.toBeInTheDocument(); + expect(rendered.queryByRole('button', { name: /^install/i })).not.toBeInTheDocument(); + rendered.unmount(); // Should not show an "Uninstall" button rendered = renderPluginDetails({ id, isInstalled: true }); - expect(await rendered.queryByRole('button', { name: /^uninstall/i })).not.toBeInTheDocument(); + expect(rendered.queryByRole('button', { name: /^uninstall/i })).not.toBeInTheDocument(); + rendered.unmount(); // Should not show an "Update" button rendered = renderPluginDetails({ id, isInstalled: true, hasUpdate: true }); - expect(await rendered.queryByRole('button', { name: /^update/i })).not.toBeInTheDocument(); + expect(rendered.queryByRole('button', { name: /^update/i })).not.toBeInTheDocument(); }); it('should display a "Create" button as a post installation step for installed data source plugins', async () => { diff --git a/public/app/features/query/components/QueryGroup.test.tsx b/public/app/features/query/components/QueryGroup.test.tsx index cc3f2ba70a3..0622a48c872 100644 --- a/public/app/features/query/components/QueryGroup.test.tsx +++ b/public/app/features/query/components/QueryGroup.test.tsx @@ -1,4 +1,5 @@ -import { act, render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import React from 'react'; import config from 'app/core/config'; @@ -37,10 +38,13 @@ jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => { }); describe('QueryGroup', () => { + // QueryGroup relies on this being present + Object.defineProperty(HTMLElement.prototype, 'scrollTo', { value: jest.fn() }); + beforeEach(() => { - jest.useFakeTimers(); config.expressionsEnabled = true; }); + it('Should add expression on click', async () => { renderScenario({}); @@ -48,8 +52,10 @@ describe('QueryGroup', () => { const queryRowsContainer = await screen.findByTestId('query-editor-rows'); expect(queryRowsContainer.children.length).toBe(2); - await addExpressionButton.click(); - expect(queryRowsContainer.children.length).toBe(3); + await userEvent.click(addExpressionButton); + await waitFor(() => { + expect(queryRowsContainer.children.length).toBe(3); + }); }); it('Should add query on click', async () => { @@ -59,9 +65,11 @@ describe('QueryGroup', () => { const queryRowsContainer = await screen.findByTestId('query-editor-rows'); expect(queryRowsContainer.children.length).toBe(2); - await addQueryButton.click(); + await userEvent.click(addQueryButton); - expect(queryRowsContainer.children.length).toBe(3); + await waitFor(() => { + expect(queryRowsContainer.children.length).toBe(3); + }); }); it('New expression should be expanded', async () => { @@ -69,14 +77,16 @@ describe('QueryGroup', () => { const addExpressionButton = await screen.findByTestId('query-tab-add-expression'); const queryRowsContainer = await screen.findByTestId('query-editor-rows'); - await addExpressionButton.click(); + await userEvent.click(addExpressionButton); const lastQueryEditorRow = (await screen.findAllByTestId('query-editor-row')).at(-1); const lastEditorToggleRow = (await screen.findAllByLabelText('toggle collapse and expand query row')).at(-1); expect(lastEditorToggleRow?.getAttribute('aria-expanded')).toBe('true'); expect(lastQueryEditorRow?.firstElementChild?.children.length).toBe(2); - expect(queryRowsContainer.children.length).toBe(3); + await waitFor(() => { + expect(queryRowsContainer.children.length).toBe(3); + }); }); it('New query should be expanded', async () => { @@ -84,23 +94,23 @@ describe('QueryGroup', () => { const addQueryButton = await screen.findByTestId('query-tab-add-query'); const queryRowsContainer = await screen.findByTestId('query-editor-rows'); - await addQueryButton.click(); + await userEvent.click(addQueryButton); const lastQueryEditorRow = (await screen.findAllByTestId('query-editor-row')).at(-1); const lastEditorToggleRow = (await screen.findAllByLabelText('toggle collapse and expand query row')).at(-1); expect(lastEditorToggleRow?.getAttribute('aria-expanded')).toBe('true'); expect(lastQueryEditorRow?.firstElementChild?.children.length).toBe(2); - expect(queryRowsContainer.children.length).toBe(3); + await waitFor(() => { + expect(queryRowsContainer.children.length).toBe(3); + }); }); it('Should open data source help modal', async () => { renderScenario({}); const openHelpButton = await screen.findByTestId('query-tab-help-button'); - await act(async () => { - await openHelpButton.click(); - }); + await userEvent.click(openHelpButton); const helpModal = await screen.findByRole('dialog'); expect(helpModal).toBeInTheDocument(); @@ -109,6 +119,7 @@ describe('QueryGroup', () => { it('Should not show add expression button when expressions are disabled', async () => { config.expressionsEnabled = false; renderScenario({}); + await screen.findByTestId('query-tab-add-query'); const addExpressionButton = screen.queryByTestId('query-tab-add-expression'); expect(addExpressionButton).not.toBeInTheDocument(); }); diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx index c8983e1e10e..ee24b71b71e 100644 --- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx @@ -22,7 +22,7 @@ const variableOptionGroup = { options: [], }; -describe('LogsQueryEdiutor', () => { +describe('LogsQueryEditor', () => { const originalScrollIntoView = window.HTMLElement.prototype.scrollIntoView; beforeEach(() => { @@ -50,13 +50,13 @@ describe('LogsQueryEdiutor', () => { ); const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); - resourcePickerButton.click(); + await userEvent.click(resourcePickerButton); const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); - subscriptionButton.click(); + await userEvent.click(subscriptionButton); const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); - resourceGroupButton.click(); + await userEvent.click(resourceGroupButton); const checkbox = await screen.findByLabelText('web-server'); await userEvent.click(checkbox); @@ -98,13 +98,13 @@ describe('LogsQueryEdiutor', () => { ); const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); - resourcePickerButton.click(); + await userEvent.click(resourcePickerButton); const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); - subscriptionButton.click(); + await userEvent.click(subscriptionButton); const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); - resourceGroupButton.click(); + await userEvent.click(resourceGroupButton); const checkbox = await screen.findByLabelText('web-server'); await userEvent.click(checkbox); @@ -131,13 +131,13 @@ describe('LogsQueryEdiutor', () => { ); const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); - resourcePickerButton.click(); + await userEvent.click(resourcePickerButton); const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); - subscriptionButton.click(); + await userEvent.click(subscriptionButton); const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); - resourceGroupButton.click(); + await userEvent.click(resourceGroupButton); const checkbox = await screen.findByLabelText('web-server'); await userEvent.click(checkbox); @@ -164,17 +164,17 @@ describe('LogsQueryEdiutor', () => { ); const resourcePickerButton = await screen.findByRole('button', { name: 'Select a resource' }); - resourcePickerButton.click(); + await userEvent.click(resourcePickerButton); const advancedSection = screen.getByText('Advanced'); - advancedSection.click(); + await userEvent.click(advancedSection); const advancedInput = await screen.findByTestId('input-advanced-resource-picker-1'); // const advancedInput = await screen.findByLabelText('Resource URI(s)'); await userEvent.type(advancedInput, '/subscriptions/def-123'); const applyButton = screen.getByRole('button', { name: 'Apply' }); - applyButton.click(); + await userEvent.click(applyButton); expect(onChange).toBeCalledWith( expect.objectContaining({ diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.test.tsx index ae526502b18..9358c52ea46 100644 --- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.test.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.test.tsx @@ -89,6 +89,10 @@ describe('AzureMonitor ResourcePicker', () => { it('should show a subscription as selected if there is one saved', async () => { render(); + await waitFor(async () => { + const subscriptionCheckboxes = await screen.findAllByLabelText('Dev Subscription'); + expect(subscriptionCheckboxes.length).toBe(2); + }); const subscriptionCheckboxes = await screen.findAllByLabelText('Dev Subscription'); expect(subscriptionCheckboxes.length).toBe(2); expect(subscriptionCheckboxes[0]).toBeChecked(); @@ -133,7 +137,7 @@ describe('AzureMonitor ResourcePicker', () => { const expandSubscriptionButton = await screen.findByLabelText('Expand Primary Subscription'); expect(expandSubscriptionButton).toBeInTheDocument(); expect(screen.queryByLabelText('A Great Resource Group')).not.toBeInTheDocument(); - expandSubscriptionButton.click(); + await userEvent.click(expandSubscriptionButton); expect(await screen.findByLabelText('A Great Resource Group')).toBeInTheDocument(); }); @@ -143,10 +147,10 @@ describe('AzureMonitor ResourcePicker', () => { const subscriptionCheckbox = await screen.findByLabelText('Primary Subscription'); expect(subscriptionCheckbox).toBeInTheDocument(); expect(subscriptionCheckbox).not.toBeChecked(); - subscriptionCheckbox.click(); + await userEvent.click(subscriptionCheckbox); const applyButton = screen.getByRole('button', { name: 'Apply' }); expect(applyButton).toBeEnabled(); - applyButton.click(); + await userEvent.click(applyButton); expect(onApply).toBeCalledTimes(1); expect(onApply).toBeCalledWith(['/subscriptions/def-123']); }); @@ -157,9 +161,9 @@ describe('AzureMonitor ResourcePicker', () => { const subscriptionCheckbox = await screen.findAllByLabelText('Primary Subscription'); expect(subscriptionCheckbox).toHaveLength(2); expect(subscriptionCheckbox.at(0)).toBeChecked(); - subscriptionCheckbox.at(0)?.click(); + await userEvent.click(subscriptionCheckbox.at(0)!); const applyButton = screen.getByRole('button', { name: 'Apply' }); - applyButton.click(); + await userEvent.click(applyButton); expect(onApply).toBeCalledTimes(1); expect(onApply).toBeCalledWith([]); }); @@ -172,9 +176,9 @@ describe('AzureMonitor ResourcePicker', () => { const subscriptionCheckbox = await screen.findAllByLabelText('A Great Resource Group'); expect(subscriptionCheckbox).toHaveLength(2); expect(subscriptionCheckbox.at(0)).toBeChecked(); - subscriptionCheckbox.at(0)?.click(); + await userEvent.click(subscriptionCheckbox.at(0)!); const applyButton = screen.getByRole('button', { name: 'Apply' }); - applyButton.click(); + await userEvent.click(applyButton); expect(onApply).toBeCalledTimes(1); expect(onApply).toBeCalledWith([]); }); @@ -186,15 +190,15 @@ describe('AzureMonitor ResourcePicker', () => { const subscriptionButton = await screen.findByRole('button', { name: 'Expand Primary Subscription' }); expect(subscriptionButton).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Expand A Great Resource Group' })).not.toBeInTheDocument(); - subscriptionButton.click(); + await userEvent.click(subscriptionButton); const resourceGroupButton = await screen.findByRole('button', { name: 'Expand A Great Resource Group' }); - resourceGroupButton.click(); + await userEvent.click(resourceGroupButton); const checkbox = await screen.findByLabelText('web-server'); await userEvent.click(checkbox); expect(checkbox).toBeChecked(); const applyButton = screen.getByRole('button', { name: 'Apply' }); - applyButton.click(); + await userEvent.click(applyButton); expect(onApply).toBeCalledTimes(1); expect(onApply).toBeCalledWith([ @@ -231,9 +235,9 @@ describe('AzureMonitor ResourcePicker', () => { const checkbox = await screen.findAllByLabelText('web-server'); expect(checkbox).toHaveLength(2); expect(checkbox.at(0)).toBeChecked(); - checkbox.at(0)?.click(); + await userEvent.click(checkbox.at(0)!); const applyButton = screen.getByRole('button', { name: 'Apply' }); - applyButton.click(); + await userEvent.click(applyButton); expect(onApply).toBeCalledTimes(1); expect(onApply).toBeCalledWith([]); }); @@ -269,13 +273,11 @@ describe('AzureMonitor ResourcePicker', () => { it('renders a loading state while waiting for search results', async () => { const rpd = createMockResourcePickerData(); - rpd.search = jest.fn().mockImplementation(() => { - return new Promise((resolve) => { - setTimeout(() => { - return resolve(mockSearchResults()); - }, 1); // purposely slow down call by a tick so as to force a loading state - }); + let promiseResolver: (value: unknown) => void = () => {}; + const promiseToResolve = new Promise((resolve) => { + promiseResolver = resolve; }); + rpd.search = jest.fn().mockImplementation(() => promiseToResolve); render(); @@ -287,6 +289,9 @@ describe('AzureMonitor ResourcePicker', () => { const loading = await screen.findByText('Loading...'); expect(loading).toBeInTheDocument(); + // resolve the promise + promiseResolver(mockSearchResults()); + const searchResult = await screen.findByLabelText('search-result'); expect(searchResult).toBeInTheDocument(); @@ -330,7 +335,7 @@ describe('AzureMonitor ResourcePicker', () => { /> ); const subscriptionExpand = await screen.findByLabelText('Expand Primary Subscription'); - await subscriptionExpand.click(); + await userEvent.click(subscriptionExpand); const error = await screen.findByRole('alert'); expect(error).toHaveTextContent('An error occurred while requesting resources from Azure Monitor'); expect(error).toHaveTextContent( diff --git a/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx index a0f8bbcbfe3..7947503f9b8 100644 --- a/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx @@ -47,7 +47,7 @@ describe('VariableEditor:', () => { render(); await waitFor(() => screen.getByLabelText('select query type')); expect(screen.getByLabelText('select query type')).toBeInTheDocument(); - screen.getByLabelText('select query type').click(); + await userEvent.click(screen.getByLabelText('select query type')); await select(screen.getByLabelText('select query type'), 'Grafana Query Function', { container: document.body, }); @@ -185,7 +185,7 @@ describe('VariableEditor:', () => { rerender: (ui: React.ReactElement) => void ) => { openMenu(screen.getByLabelText(label)); - screen.getByText(text).click(); + await userEvent.click(screen.getByText(text)); // Simulate onChange behavior const newQuery = onChange.mock.calls.at(-1)[0]; rerender(); @@ -226,7 +226,7 @@ describe('VariableEditor:', () => { // Select a subscription openMenu(screen.getByLabelText('select subscription')); await waitFor(() => expect(screen.getByText('Primary Subscription')).toBeInTheDocument()); - screen.getByText('Template Variables').click(); + await userEvent.click(screen.getByText('Template Variables')); // Simulate onChange behavior const lastQuery = onChange.mock.calls.at(-1)[0]; rerender(); diff --git a/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.test.tsx index b408714dc49..ec92fe09c53 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.test.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.test.tsx @@ -45,13 +45,13 @@ describe('VisualMetricQueryEditor', () => { render(); const service = await screen.findByLabelText('Service'); - await openMenu(service); + openMenu(service); await act(async () => { await select(service, 'Srv', { container: document.body }); - expect(onChange).toBeCalledWith( - expect.objectContaining({ filters: ['metric.type', '=', mockMetricDescriptor.type] }) - ); }); + expect(onChange).toBeCalledWith( + expect.objectContaining({ filters: ['metric.type', '=', mockMetricDescriptor.type] }) + ); }); it('can select a metric name', async () => { @@ -66,19 +66,19 @@ describe('VisualMetricQueryEditor', () => { render(); const service = await screen.findByLabelText('Service'); - await openMenu(service); + openMenu(service); await act(async () => { await select(service, 'Srv', { container: document.body }); }); const metricName = await screen.findByLabelText('Metric name'); - await openMenu(metricName); + openMenu(metricName); await waitFor(() => expect(document.body).toHaveTextContent('metricName_test')); await act(async () => { await select(metricName, 'metricName_test', { container: document.body }); - expect(onChange).toBeCalledWith( - expect.objectContaining({ filters: ['metric.type', '=', mockMetricDescriptor.type] }) - ); }); + expect(onChange).toBeCalledWith( + expect.objectContaining({ filters: ['metric.type', '=', mockMetricDescriptor.type] }) + ); }); it('should render available metric options according to the selected service', async () => { @@ -114,12 +114,12 @@ describe('VisualMetricQueryEditor', () => { render(); const service = await screen.findByLabelText('Service'); - await openMenu(service); + openMenu(service); await act(async () => { await select(service, 'Srv A', { container: document.body }); }); const metricName = await screen.findByLabelText('Metric name'); - await openMenu(metricName); + openMenu(metricName); const metricNameOptions = screen.getByLabelText('Select options menu'); expect(within(metricNameOptions).getByText('description_metric1')).toBeInTheDocument(); @@ -129,7 +129,7 @@ describe('VisualMetricQueryEditor', () => { expect(within(metricNameOptions).queryByText('displayName_metric3')).not.toBeInTheDocument(); expect(within(metricNameOptions).queryByText('description_metric3')).not.toBeInTheDocument(); - await openMenu(service); + openMenu(service); await act(async () => { await select(service, 'Srv B', { container: document.body }); }); @@ -172,7 +172,7 @@ describe('VisualMetricQueryEditor', () => { render(); const service = await screen.findByLabelText('Service'); - await openMenu(service); + openMenu(service); expect(screen.getAllByLabelText('Select option').length).toEqual(2); }); @@ -233,8 +233,8 @@ describe('VisualMetricQueryEditor', () => { ); expect(query).toEqual(defaultQuery); expect(document.body).toHaveTextContent('metric.test_label'); - expect(await screen.queryByText('Delta')).not.toBeInTheDocument(); - expect(await screen.queryByText('metric.test_groupby')).not.toBeInTheDocument(); + expect(screen.queryByText('Delta')).not.toBeInTheDocument(); + expect(screen.queryByText('metric.test_groupby')).not.toBeInTheDocument(); }); it('updates labels on time range change', async () => { @@ -257,30 +257,28 @@ describe('VisualMetricQueryEditor', () => { ); const service = await screen.findByLabelText('Service'); - await openMenu(service); + openMenu(service); await act(async () => { await select(service, 'Srv', { container: document.body }); }); const metricName = await screen.findByLabelText('Metric name'); - await openMenu(metricName); + openMenu(metricName); await waitFor(() => expect(document.body).toHaveTextContent('metricName')); await act(async () => { await select(metricName, 'metricName', { container: document.body }); }); const groupBy = await screen.findByLabelText('Group by'); - await openMenu(groupBy); + openMenu(groupBy); await waitFor(() => expect(document.body).toHaveTextContent('metric.test_groupby')); - await act(async () => { - timeSrv.setTime({ from: 'now-12h', to: 'now' }); - const datasourceUpdated = createMockDatasource({ - timeSrv, - getLabels: jest.fn().mockResolvedValue({ 'metric.test_groupby_1': '' }), - }); - rerender( - - ); - await openMenu(groupBy); - await waitFor(() => expect(document.body).toHaveTextContent('metric.test_groupby_1')); + timeSrv.setTime({ from: 'now-12h', to: 'now' }); + const datasourceUpdated = createMockDatasource({ + timeSrv, + getLabels: jest.fn().mockResolvedValue({ 'metric.test_groupby_1': '' }), }); + rerender( + + ); + openMenu(groupBy); + await waitFor(() => expect(document.body).toHaveTextContent('metric.test_groupby_1')); }); }); diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor.test.tsx index dd1ad95e8d6..61542d80086 100644 --- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor.test.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor.test.tsx @@ -1,4 +1,5 @@ -import { act, fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import React from 'react'; import { QueryEditorProps } from '@grafana/data'; @@ -64,10 +65,8 @@ describe('QueryEditor should render right editor', () => { region: 'default', returnData: false, }; - await act(async () => { - render(); - }); - expect(screen.getByText('Metric name')).toBeInTheDocument(); + render(); + expect(await screen.findByText('Metric name')).toBeInTheDocument(); }); }); @@ -91,11 +90,9 @@ describe('QueryEditor should render right editor', () => { refId: 'A', region: 'ap-northeast-2', statistics: 'Average', - } as any; - await act(async () => { - render(); - }); - expect(screen.getByText('Metric name')).toBeInTheDocument(); + } as CloudWatchQuery; + render(); + expect(await screen.findByText('Metric name')).toBeInTheDocument(); }); }); @@ -119,11 +116,9 @@ describe('QueryEditor should render right editor', () => { refId: 'A', region: 'ap-northeast-2', statistic: 'Average', - } as any; - await act(async () => { - render(); - }); - expect(screen.getByText('Select Log Groups')).toBeInTheDocument(); + } as CloudWatchQuery; + render(); + expect(await screen.findByText('Select Log Groups')).toBeInTheDocument(); }); }); @@ -146,11 +141,9 @@ describe('QueryEditor should render right editor', () => { refId: 'B', region: '$region', statistic: 'Average', - } as any; - await act(async () => { - render(); - }); - expect(screen.getByText('Metric name')).toBeInTheDocument(); + } as CloudWatchQuery; + render(); + expect(await screen.findByText('Metric name')).toBeInTheDocument(); }); }); @@ -191,10 +184,8 @@ describe('QueryEditor should render right editor', () => { test.each(cases)('$name', async ({ query, toggle }) => { config.featureToggles.cloudWatchCrossAccountQuerying = toggle; - await act(async () => { - render(); - }); - expect(await screen.getByText('Monitoring account')).toBeInTheDocument(); + render(); + expect(await screen.findByText('Monitoring account')).toBeInTheDocument(); }); }); @@ -224,34 +215,29 @@ describe('QueryEditor should render right editor', () => { ]; test.each(cases)('$name', async ({ query, toggle }) => { config.featureToggles.cloudWatchCrossAccountQuerying = toggle; - await act(async () => { - render(); - }); - expect(await screen.queryByText('Monitoring account')).toBeNull(); + render(); + expect(await screen.findByText('Run queries')).toBeInTheDocument(); + expect(screen.queryByText('Monitoring account')).toBeNull(); }); }); }); describe('QueryHeader', () => { it('should display metric actions in header when metric query is used', async () => { - await act(async () => { - render(); - }); + render(); + expect(await screen.findByText('CloudWatch Metrics')).toBeInTheDocument(); expect(screen.getByLabelText(/Region.*/)).toBeInTheDocument(); - expect(screen.getByText('CloudWatch Metrics')).toBeInTheDocument(); expect(screen.getByLabelText('Builder')).toBeInTheDocument(); expect(screen.getByLabelText('Code')).toBeInTheDocument(); expect(screen.getByText('Metric Query')).toBeInTheDocument(); }); it('should display metric actions in header when metric query is used', async () => { - await act(async () => { - render(); - }); + render(); + expect(await screen.findByText('CloudWatch Logs')).toBeInTheDocument(); expect(screen.getByLabelText(/Region.*/)).toBeInTheDocument(); - expect(screen.getByText('CloudWatch Logs')).toBeInTheDocument(); expect(screen.queryByLabelText('Builder')).not.toBeInTheDocument(); expect(screen.queryByLabelText('Code')).not.toBeInTheDocument(); expect(screen.queryByText('Metric Query')).not.toBeInTheDocument(); @@ -260,42 +246,33 @@ describe('QueryEditor should render right editor', () => { describe('metrics editor should handle editor modes correctly', () => { it('when metric query type is metric search and editor mode is builder', async () => { - await act(async () => { - render(); - }); + render(); - expect(screen.getByText('Metric Search')).toBeInTheDocument(); + expect(await screen.findByText('Metric Search')).toBeInTheDocument(); const radio = screen.getByLabelText('Builder'); expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); }); it('when metric query type is metric search and editor mode is raw', async () => { - await act(async () => { - render(); - }); - expect(screen.getByText('Metric Search')).toBeInTheDocument(); + render(); + + expect(await screen.findByText('Metric Search')).toBeInTheDocument(); const radio = screen.getByLabelText('Code'); expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); }); it('when metric query type is metric query and editor mode is builder', async () => { - await act(async () => { - await act(async () => { - render(); - }); + render(); - expect(screen.getByText('Metric Query')).toBeInTheDocument(); - const radio = screen.getByLabelText('Builder'); - expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); - }); + expect(await screen.findByText('Metric Query')).toBeInTheDocument(); + const radio = screen.getByLabelText('Builder'); + expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); }); it('when metric query type is metric query and editor mode is raw', async () => { - await act(async () => { - render(); - }); + render(); - expect(screen.getByText('Metric Query')).toBeInTheDocument(); + expect(await screen.findByText('Metric Query')).toBeInTheDocument(); const radio = screen.getByLabelText('Code'); expect(radio instanceof HTMLInputElement && radio.checked).toBeTruthy(); }); @@ -315,12 +292,11 @@ describe('QueryEditor should render right editor', () => { // the modal should not be shown unless the code editor is "dirty", so need to trigger a change const codeEditorElement = screen.getByLabelText(FAKE_EDITOR_LABEL); - fireEvent.change(codeEditorElement, { target: { value: 'select * from ' } }); + await userEvent.clear(codeEditorElement); + await userEvent.type(codeEditorElement, 'select * from '); const builderElement = screen.getByLabelText('Builder'); expect(builderElement).toBeInTheDocument(); - await act(async () => { - await builderElement.click(); - }); + await userEvent.click(builderElement); const modalTitleElem = screen.getByText('Are you sure?'); expect(modalTitleElem).toBeInTheDocument(); @@ -332,9 +308,7 @@ describe('QueryEditor should render right editor', () => { ); const builderElement = screen.getByLabelText('Builder'); expect(builderElement).toBeInTheDocument(); - await act(async () => { - await builderElement.click(); - }); + await userEvent.click(builderElement); expect(screen.queryByText('Are you sure?')).toBeNull(); }); @@ -343,9 +317,7 @@ describe('QueryEditor should render right editor', () => { const builderElement = screen.getByLabelText('Builder'); expect(builderElement).toBeInTheDocument(); - await act(async () => { - await builderElement.click(); - }); + await userEvent.click(builderElement); expect(screen.queryByText('Are you sure?')).toBeNull(); }); }); diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx index 3ce461356ab..4cf327edb2b 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx @@ -88,19 +88,21 @@ describe('LokiQueryEditorSelector', () => { await expectBuilder(); }); - it('shows Run Queries button in Dashboards', () => { + it('shows Run Queries button in Dashboards', async () => { renderWithProps({}, { app: CoreApp.Dashboard }); - expectRunQueriesButton(); + await expectRunQueriesButton(); }); it('hides Run Queries button in Explore', async () => { renderWithProps({}, { app: CoreApp.Explore }); + await expectCodeEditor(); expectNoRunQueriesButton(); }); it('hides Run Queries button in Correlations Page', async () => { renderWithProps({}, { app: CoreApp.Correlations }); - await expectNoRunQueriesButton(); + await expectCodeEditor(); + expectNoRunQueriesButton(); }); it('changes to builder mode', async () => { @@ -128,7 +130,7 @@ describe('LokiQueryEditorSelector', () => { it('Can enable explain', async () => { renderWithMode(QueryEditorMode.Builder); expect(screen.queryByText(EXPLAIN_LABEL_FILTER_CONTENT)).not.toBeInTheDocument(); - screen.getByLabelText('Explain query').click(); + await userEvent.click(screen.getByLabelText('Explain query')); expect(await screen.findByText(EXPLAIN_LABEL_FILTER_CONTENT)).toBeInTheDocument(); }); @@ -198,8 +200,8 @@ async function expectBuilder() { expect(await screen.findByText('Label filters')).toBeInTheDocument(); } -function expectRunQueriesButton() { - expect(screen.getByRole('button', { name: /run queries/i })).toBeInTheDocument(); +async function expectRunQueriesButton() { + expect(await screen.findByRole('button', { name: /run queries/i })).toBeInTheDocument(); } function expectNoRunQueriesButton() { diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx index 5f48c504af6..ad9d01d6722 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx @@ -1,4 +1,4 @@ -import { act, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import { DataSourcePluginMeta } from '@grafana/data'; @@ -39,9 +39,7 @@ describe('LokiQueryBuilderContainer', () => { render(); const selector = await screen.findByLabelText('selector'); expect(selector.textContent).toBe('{job="testjob"}'); - await act(async () => { - await addOperation('Range functions', 'Rate'); - }); + await addOperation('Range functions', 'Rate'); expect(await screen.findByText('Rate')).toBeInTheDocument(); expect(props.onChange).toBeCalledWith({ expr: 'rate({job="testjob"} [$__interval])', diff --git a/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.testUtils.ts b/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.testUtils.ts index aabbc820ac1..c0e2a6b93b2 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.testUtils.ts +++ b/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.testUtils.ts @@ -1,16 +1,18 @@ -import { screen, fireEvent } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; export async function addOperation(section: string, op: string) { const addOperationButton = screen.getByTitle('Add operation'); expect(addOperationButton).toBeInTheDocument(); await userEvent.click(addOperationButton); - const sectionItem = screen.getByTitle(section); + const sectionItem = await screen.findByTitle(section); expect(sectionItem).toBeInTheDocument(); // Weirdly the await userEvent.click doesn't work here, it reports the item has pointer-events: none. Don't see that // anywhere when debugging so not sure what style is it picking up. - fireEvent.click(sectionItem.children[0]); + await userEvent.click(sectionItem.children[0], { pointerEventsCheck: 0 }); const opItem = screen.getByTitle(op); expect(opItem).toBeInTheDocument(); - fireEvent.click(opItem); + // Weirdly the await userEvent.click doesn't work here, it reports the item has pointer-events: none. Don't see that + // anywhere when debugging so not sure what style is it picking up. + await userEvent.click(opItem, { pointerEventsCheck: 0 }); } diff --git a/public/app/plugins/panel/flamegraph/components/FlameGraphContainer.test.tsx b/public/app/plugins/panel/flamegraph/components/FlameGraphContainer.test.tsx index c8a1f53eedf..f39ff0c5fb3 100644 --- a/public/app/plugins/panel/flamegraph/components/FlameGraphContainer.test.tsx +++ b/public/app/plugins/panel/flamegraph/components/FlameGraphContainer.test.tsx @@ -1,5 +1,5 @@ -import '@testing-library/jest-dom'; import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import React from 'react'; import { CoreApp, MutableDataFrame } from '@grafana/data'; @@ -20,6 +20,7 @@ describe('FlameGraphContainer', () => { // Needed for AutoSizer to work in test Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { value: 500 }); Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { value: 500 }); + Object.defineProperty(HTMLElement.prototype, 'clientWidth', { value: 500 }); const FlameGraphContainerWithProps = () => { const flameGraphData = new MutableDataFrame(data); @@ -38,11 +39,11 @@ describe('FlameGraphContainer', () => { it('should update search when row selected in top table', async () => { render(); - screen.getAllByRole('row')[1].click(); + await userEvent.click((await screen.findAllByRole('row'))[1]); expect(screen.getByDisplayValue('net/http.HandlerFunc.ServeHTTP')).toBeInTheDocument(); - screen.getAllByRole('row')[2].click(); + await userEvent.click(screen.getAllByRole('row')[2]); expect(screen.getByDisplayValue('total')).toBeInTheDocument(); - screen.getAllByRole('row')[2].click(); + await userEvent.click(screen.getAllByRole('row')[2]); expect(screen.queryByDisplayValue('total')).not.toBeInTheDocument(); }); @@ -59,15 +60,15 @@ describe('FlameGraphContainer', () => { expect(screen.getByTestId('flameGraph')).toBeDefined(); expect(screen.getByTestId('topTable')).toBeDefined(); - screen.getByText(/Top Table/).click(); + await userEvent.click(screen.getByText(/Top Table/)); expect(screen.queryByTestId('flameGraph')).toBeNull(); expect(screen.getByTestId('topTable')).toBeDefined(); - screen.getByText(/Flame Graph/).click(); + await userEvent.click(screen.getByText(/Flame Graph/)); expect(screen.getByTestId('flameGraph')).toBeDefined(); expect(screen.queryByTestId('topTable')).toBeNull(); - screen.getByText(/Both/).click(); + await userEvent.click(screen.getByText(/Both/)); expect(screen.getByTestId('flameGraph')).toBeDefined(); expect(screen.getByTestId('topTable')).toBeDefined(); });