diff --git a/public/app/core/navigation/RouterDebugger.tsx b/public/app/core/navigation/RouterDebugger.tsx
index abc6f9f66cc..f1e165edc8b 100644
--- a/public/app/core/navigation/RouterDebugger.tsx
+++ b/public/app/core/navigation/RouterDebugger.tsx
@@ -1,4 +1,4 @@
-import { Link } from 'react-router-dom';
+import { Link } from 'react-router-dom-v5-compat';
import { getAppRoutes } from '../../routes/routes';
import { PageContents } from '../components/Page/PageContents';
diff --git a/public/app/features/alerting/unified/MuteTimings.test.tsx b/public/app/features/alerting/unified/MuteTimings.test.tsx
index 6e3eba6611d..ad600a490f5 100644
--- a/public/app/features/alerting/unified/MuteTimings.test.tsx
+++ b/public/app/features/alerting/unified/MuteTimings.test.tsx
@@ -1,7 +1,6 @@
import { InitialEntry } from 'history';
import { last } from 'lodash';
-import { ReactNode } from 'react';
-import { Route } from 'react-router';
+import { Route, Routes } from 'react-router-dom-v5-compat';
import { render, screen, userEvent, within } from 'test/test-utils';
import { byRole, byTestId, byText } from 'testing-library-selector';
@@ -24,14 +23,16 @@ import { grantUserPermissions, mockDataSource } from './mocks';
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
const indexPageText = 'redirected routes page';
-const renderMuteTimings = (component: ReactNode, location?: InitialEntry) => {
+const Index = () => {
+ return
{indexPageText}
;
+};
+const renderMuteTimings = (location?: InitialEntry) => {
render(
- <>
-
- {indexPageText}
-
- {component}
- >,
+
+ } />
+ } />
+ } />
+ ,
{ historyOptions: location ? { initialEntries: [location] } : undefined }
);
};
@@ -213,7 +214,7 @@ describe('Mute timings', () => {
it('creates a new mute timing, with mute_time_intervals in config', async () => {
const capture = captureRequests();
- renderMuteTimings();
+ renderMuteTimings('/alerting/routes/new');
await screen.findByText(/add mute timing/i);
@@ -240,9 +241,7 @@ describe('Mute timings', () => {
it('creates a new mute timing, with time_intervals in config', async () => {
const capture = captureRequests();
setAlertmanagerConfig(dataSources.am.uid, defaultConfigWithNewTimeIntervalsField);
- renderMuteTimings(, {
- search: `?alertmanager=${dataSources.am.name}`,
- });
+ renderMuteTimings({ pathname: '/alerting/routes/new', search: `?alertmanager=${dataSources.am.name}` });
await fillOutForm({
name: 'maintenance period',
@@ -264,9 +263,7 @@ describe('Mute timings', () => {
it('creates a new mute timing, with time_intervals and mute_time_intervals in config', async () => {
setAlertmanagerConfig(dataSources.am.uid, defaultConfigWithBothTimeIntervalsField);
- renderMuteTimings(, {
- search: `?alertmanager=${dataSources.am.name}`,
- });
+ renderMuteTimings({ pathname: '/alerting/routes/new', search: `?alertmanager=${dataSources.am.name}` });
expect(ui.nameField.get()).toBeInTheDocument();
@@ -285,7 +282,8 @@ describe('Mute timings', () => {
it('prepopulates the form when editing a mute timing', async () => {
const capture = captureRequests();
- renderMuteTimings(, {
+ renderMuteTimings({
+ pathname: '/alerting/routes/edit',
search: `?muteName=${encodeURIComponent(muteTimeInterval.name)}`,
});
@@ -325,7 +323,7 @@ describe('Mute timings', () => {
});
it('form is invalid with duplicate mute timing name', async () => {
- renderMuteTimings();
+ renderMuteTimings('/alerting/routes/new');
await fillOutForm({ name: muteTimeInterval.name, days: '1' });
@@ -335,7 +333,8 @@ describe('Mute timings', () => {
});
it('replaces mute timings in routes when the mute timing name is changed', async () => {
- renderMuteTimings(, {
+ renderMuteTimings({
+ pathname: '/alerting/routes/edit',
search: `?muteName=${encodeURIComponent(muteTimeInterval.name)}`,
});
@@ -350,7 +349,8 @@ describe('Mute timings', () => {
});
it('shows error when mute timing does not exist', async () => {
- renderMuteTimings(, {
+ renderMuteTimings({
+ pathname: '/alerting/routes/edit',
search: `?alertmanager=${GRAFANA_RULES_SOURCE_NAME}&muteName=${'does not exist'}`,
});
@@ -363,7 +363,7 @@ describe('Mute timings', () => {
});
it('allows creation of new mute timings', async () => {
- renderMuteTimings();
+ renderMuteTimings('/alerting/routes/new');
await fillOutForm({ name: 'a new mute timing' });
@@ -372,7 +372,8 @@ describe('Mute timings', () => {
});
it('shows error when mute timing does not exist', async () => {
- renderMuteTimings(, {
+ renderMuteTimings({
+ pathname: '/alerting/routes/edit',
search: `?alertmanager=${GRAFANA_RULES_SOURCE_NAME}&muteName=${TIME_INTERVAL_NAME_HAPPY_PATH + '_force_breakage'}`,
});
@@ -380,7 +381,8 @@ describe('Mute timings', () => {
});
it('loads edit form correctly and allows saving', async () => {
- renderMuteTimings(, {
+ renderMuteTimings({
+ pathname: '/alerting/routes/edit',
search: `?alertmanager=${GRAFANA_RULES_SOURCE_NAME}&muteName=${TIME_INTERVAL_NAME_HAPPY_PATH}`,
});
@@ -389,7 +391,8 @@ describe('Mute timings', () => {
});
it('loads view form for provisioned interval', async () => {
- renderMuteTimings(, {
+ renderMuteTimings({
+ pathname: '/alerting/routes/edit',
search: `?muteName=${TIME_INTERVAL_NAME_FILE_PROVISIONED}`,
});
diff --git a/public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx b/public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx
index 9f0b8b7620b..b0509065b58 100644
--- a/public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx
+++ b/public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx
@@ -1,5 +1,5 @@
import 'core-js/stable/structured-clone';
-import { Route } from 'react-router';
+import { Routes, Route } from 'react-router-dom-v5-compat';
import { render, screen } from 'test/test-utils';
import { byLabelText, byPlaceholderText, byRole, byTestId } from 'testing-library-selector';
@@ -9,23 +9,22 @@ import { AccessControlAction } from 'app/types';
import { setupMswServer } from '../../mockApi';
import { grantUserPermissions } from '../../mocks';
-import { AlertmanagerProvider } from '../../state/AlertmanagerContext';
import { testWithFeatureToggles } from '../../test/test-utils';
import NewReceiverView from './NewReceiverView';
setupMswServer();
+const Index = () => {
+ return redirected
;
+};
+
const renderForm = () =>
render(
-
-
-
-
-
- redirected
-
- ,
+
+ } />
+ } />
+ ,
{
historyOptions: { initialEntries: ['/alerting/notifications/new'] },
}
diff --git a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawer.test.tsx b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawer.test.tsx
index b2772d5f856..5e7e71ee6b3 100644
--- a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawer.test.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawer.test.tsx
@@ -23,15 +23,6 @@ jest.mock('@grafana/runtime', () => ({
useChromeHeaderHeight: jest.fn(),
}));
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useLocation: jest.fn().mockReturnValue({
- pathname: '/d/dash-1',
- hash: '',
- state: null,
- }),
-}));
-
describe('ShareDrawer', () => {
it('removes shareView query param from url when it is closed', async () => {
const { dashboard } = await buildAndRenderScenario();
diff --git a/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx b/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx
index b6c94f6fa87..ab003448e23 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx
@@ -1,10 +1,9 @@
-import { fireEvent, render, screen, waitFor } from '@testing-library/react';
+import { fireEvent, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { Router } from 'react-router-dom';
import { Observable } from 'rxjs';
+import { render } from 'test/test-utils';
import { selectors } from '@grafana/e2e-selectors';
-import { locationService } from '@grafana/runtime';
import { GenAIButton, GenAIButtonProps } from './GenAIButton';
import { StreamStatus, useOpenAIStream } from './hooks';
@@ -33,11 +32,7 @@ describe('GenAIButton', () => {
const eventTrackingSrc = EventTrackingSrc.unknown;
function setup(props: GenAIButtonProps = { onGenerate, messages: [], eventTrackingSrc }) {
- return render(
-
-
-
- );
+ return render();
}
describe('when LLM plugin is not configured', () => {
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
index 374a8fd5e80..2a04e5aa045 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
@@ -28,12 +28,6 @@ standardFieldConfigEditorRegistry.setInit(getAllStandardFieldConfigs);
const mockStore = configureMockStore();
const OptionsPaneSelector = selectors.components.PanelEditor.OptionsPane;
-jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useLocation: () => ({
- pathname: 'localhost:3000/example/path',
- }),
-}));
class OptionsPaneOptionsTestScenario {
onFieldConfigsChange = jest.fn();
diff --git a/public/app/features/scopes/internal/ScopesDashboardsTreeDashboardItem.tsx b/public/app/features/scopes/internal/ScopesDashboardsTreeDashboardItem.tsx
index ce84b86c0cb..5566deebb66 100644
--- a/public/app/features/scopes/internal/ScopesDashboardsTreeDashboardItem.tsx
+++ b/public/app/features/scopes/internal/ScopesDashboardsTreeDashboardItem.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import { Link } from 'react-router-dom';
+import { Link } from 'react-router-dom-v5-compat';
import { GrafanaTheme2, urlUtil } from '@grafana/data';
import { Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx b/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx
index 748fb691ce0..24bc89e9b90 100644
--- a/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx
@@ -1,6 +1,6 @@
import { produce } from 'immer';
import { useEffect } from 'react';
-import { Link } from 'react-router-dom';
+import { Link } from 'react-router-dom-v5-compat';
import { SIGV4ConnectionConfig } from '@grafana/aws-sdk';
import { DataSourcePluginOptionsEditorProps, SelectableValue } from '@grafana/data';