AppChrome: Unify logic for chromeless pages that should not have NavBar, CommandPalette, Search etc (#62281)

* Keybindings: No global keybindings on chromeless pages

* simplify condition

* Refactoring

* Align name and file

* Move logic into AppChrome

* minor fix

* Update Page.tsx

* Fixing test

* Fixed tests

* More fixes

* Fixed more tests

* Fixing final test

* Fixed search in old nav
pull/62777/head
Torkel Ödegaard 3 years ago committed by GitHub
parent ce50168b70
commit b8e7ef48d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      public/app/AppWrapper.tsx
  2. 6
      public/app/angular/GrafanaCtrl.ts
  3. 56
      public/app/core/components/AppChrome/AppChrome.tsx
  4. 8
      public/app/core/components/AppChrome/NavLandingPage.test.tsx
  5. 9
      public/app/core/components/AppChrome/Organization/OrganizationSwitcher.test.tsx
  6. 9
      public/app/core/components/AppChrome/QuickAdd/QuickAdd.test.tsx
  7. 25
      public/app/core/components/MegaMenu/MegaMenu.test.tsx
  8. 17
      public/app/core/components/NavBar/NavBar.test.tsx
  9. 4
      public/app/core/components/NavBar/NavBar.tsx
  10. 24
      public/app/core/components/NavBar/NavBarItem.test.tsx
  11. 9
      public/app/core/components/Page/Page.test.tsx
  12. 13
      public/app/core/components/Page/Page.tsx
  13. 17
      public/app/core/components/PageNew/Page.test.tsx
  14. 7
      public/app/core/components/SharedPreferences/SharedPreferences.test.tsx
  15. 17
      public/app/core/navigation/GrafanaRoute.test.tsx
  16. 4
      public/app/core/navigation/GrafanaRoute.tsx
  17. 6
      public/app/core/services/keybindingSrv.ts
  18. 10
      public/app/features/alerting/AlertRuleList.test.tsx
  19. 16
      public/app/features/alerting/unified/AlertGroups.test.tsx
  20. 40
      public/app/features/alerting/unified/AlertsFolderView.test.tsx
  21. 14
      public/app/features/alerting/unified/AmRoutes.test.tsx
  22. 11
      public/app/features/alerting/unified/CloneRuleEditor.test.tsx
  23. 13
      public/app/features/alerting/unified/MuteTimings.test.tsx
  24. 15
      public/app/features/alerting/unified/PanelAlertTabContent.test.tsx
  25. 14
      public/app/features/alerting/unified/Receivers.test.tsx
  26. 16
      public/app/features/alerting/unified/RedirectToRuleViewer.test.tsx
  27. 15
      public/app/features/alerting/unified/RuleEditorExisting.test.tsx
  28. 13
      public/app/features/alerting/unified/RuleList.test.tsx
  29. 13
      public/app/features/alerting/unified/RuleViewer.test.tsx
  30. 13
      public/app/features/alerting/unified/Silences.test.tsx
  31. 14
      public/app/features/alerting/unified/components/admin/AlertmanagerConfig.test.tsx
  32. 12
      public/app/features/alerting/unified/components/receivers/ReceiversTable.test.tsx
  33. 6
      public/app/features/alerting/unified/components/rule-editor/AnnotationsField.test.tsx
  34. 10
      public/app/features/api-keys/ApiKeysPage.test.tsx
  35. 5
      public/app/features/commandPalette/CommandPalette.tsx
  36. 13
      public/app/features/connections/Connections.test.tsx
  37. 11
      public/app/features/correlations/CorrelationsPage.test.tsx
  38. 17
      public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
  39. 26
      public/app/features/dashboard/components/DashboardSettings/DashboardSettings.test.tsx
  40. 7
      public/app/features/datasources/components/EmptyStateNoDatasource.test.tsx
  41. 6
      public/app/features/datasources/pages/DataSourceDashboardsPage.test.tsx
  42. 11
      public/app/features/datasources/pages/DataSourcesListPage.test.tsx
  43. 6
      public/app/features/datasources/pages/EditDataSourcePage.test.tsx
  44. 7
      public/app/features/folders/FolderSettingsPage.test.tsx
  45. 8
      public/app/features/invites/SignupInvited.test.tsx
  46. 8
      public/app/features/org/OrgDetailsPage.test.tsx
  47. 11
      public/app/features/playlist/PlaylistEditPage.test.tsx
  48. 8
      public/app/features/playlist/PlaylistNewPage.test.tsx
  49. 9
      public/app/features/playlist/PlaylistPage.test.tsx
  50. 11
      public/app/features/plugins/admin/pages/Browse.test.tsx
  51. 16
      public/app/features/plugins/admin/pages/PluginDetails.test.tsx
  52. 8
      public/app/features/profile/ChangePasswordPage.test.tsx
  53. 13
      public/app/features/profile/UserProfileEditPage.test.tsx
  54. 9
      public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx
  55. 9
      public/app/features/serviceaccounts/ServiceAccountPage.test.tsx
  56. 11
      public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx
  57. 9
      public/app/features/teams/CreateTeam.test.tsx
  58. 8
      public/app/features/teams/TeamList.test.tsx
  59. 8
      public/app/features/teams/TeamPages.test.tsx
  60. 10
      public/app/routes/routes.tsx
  61. 1
      public/app/types/events.ts
  62. 33
      public/test/helpers/TestProvider.tsx
  63. 16
      public/test/helpers/alertingRuleEditor.tsx

@ -5,7 +5,6 @@ import { Router, Route, Redirect, Switch } from 'react-router-dom';
import { config, locationService, navigationLogger, reportInteraction } from '@grafana/runtime';
import { ErrorBoundaryAlert, GlobalStyles, ModalRoot, ModalsProvider, PortalContainer } from '@grafana/ui';
import { SearchWrapper } from 'app/features/search';
import { getAppRoutes } from 'app/routes/routes';
import { store } from 'app/store/store';
@ -14,13 +13,11 @@ import { loadAndInitAngularIfEnabled } from './angular/loadAndInitAngularIfEnabl
import { GrafanaApp } from './app';
import { AppChrome } from './core/components/AppChrome/AppChrome';
import { AppNotificationList } from './core/components/AppNotifications/AppNotificationList';
import { NavBar } from './core/components/NavBar/NavBar';
import { GrafanaContext } from './core/context/GrafanaContext';
import { GrafanaRoute } from './core/navigation/GrafanaRoute';
import { RouteDescriptor } from './core/navigation/types';
import { contextSrv } from './core/services/context_srv';
import { ThemeProvider } from './core/utils/ConfigProvider';
import { CommandPalette } from './features/commandPalette/CommandPalette';
import { LiveConnectionWarning } from './features/live/LiveConnectionWarning';
interface AppWrapperProps {
@ -82,23 +79,6 @@ export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState
return <Switch>{getAppRoutes().map((r) => this.renderRoute(r))}</Switch>;
}
renderNavBar() {
if (config.isPublicDashboardView || !this.state.ready || config.featureToggles.topnav) {
return null;
}
return <NavBar />;
}
commandPaletteEnabled() {
const isLoginPage = locationService.getLocation().pathname === '/login';
return config.featureToggles.commandPalette && !config.isPublicDashboardView && !isLoginPage;
}
searchBarEnabled() {
return !config.isPublicDashboardView;
}
render() {
const { app } = this.props;
const { ready } = this.state;
@ -124,18 +104,14 @@ export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState
>
<ModalsProvider>
<GlobalStyles />
{this.commandPaletteEnabled() && <CommandPalette />}
<div className="grafana-app">
<Router history={locationService.getHistory()}>
{this.renderNavBar()}
<AppChrome>
{pageBanners.map((Banner, index) => (
<Banner key={index.toString()} />
))}
<AngularRoot />
<AppNotificationList />
{this.searchBarEnabled() && <SearchWrapper />}
{ready && this.renderRoutes()}
{bodyRenderHooks.map((Hook, index) => (
<Hook key={index.toString()} />

@ -11,7 +11,7 @@ import appEvents from 'app/core/app_events';
import config from 'app/core/config';
import { ContextSrv } from 'app/core/services/context_srv';
import { initGrafanaLive } from 'app/features/live';
import { CoreEvents, AppEventEmitter, AppEventConsumer } from 'app/types';
import { AppEventEmitter, AppEventConsumer } from 'app/types';
import { UtilSrv } from './services/UtilSrv';
@ -89,10 +89,6 @@ export function grafanaAppDirective() {
// see https://github.com/zenorocha/clipboard.js/issues/155
$.fn.modal.Constructor.prototype.enforceFocus = () => {};
appEvents.on(CoreEvents.toggleSidemenuHidden, () => {
body.toggleClass('sidemenu-hidden');
});
// handle in active view state class
let lastActivity = new Date().getTime();
let activeUser = true;

@ -5,9 +5,12 @@ import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { CommandPalette } from 'app/features/commandPalette/CommandPalette';
import { SearchWrapper } from 'app/features/search';
import { KioskMode } from 'app/types';
import { MegaMenu } from '../MegaMenu/MegaMenu';
import { NavBar } from '../NavBar/NavBar';
import { NavToolbar } from './NavToolbar';
import { TopSearchBar } from './TopSearchBar';
@ -19,9 +22,21 @@ export function AppChrome({ children }: Props) {
const styles = useStyles2(getStyles);
const { chrome } = useGrafana();
const state = chrome.useState();
const featureToggles = config.featureToggles;
if (!config.featureToggles.topnav) {
return <main className="main-view">{children}</main>;
return (
<>
{!state.chromeless && (
<>
<NavBar />
<SearchWrapper />
{featureToggles.commandPalette && <CommandPalette />}
</>
)}
<main className="main-view">{children}</main>
</>
);
}
const searchBarHidden = state.searchBarHidden || state.kioskMode === KioskMode.TV;
@ -32,24 +47,33 @@ export function AppChrome({ children }: Props) {
[styles.contentChromeless]: state.chromeless,
});
// Chromeless routes are without topNav, mega menu, search & command palette
if (state.chromeless) {
return (
<main className="main-view">
<div className={contentClass}>{children}</div>
</main>
);
}
return (
<main className="main-view">
{!state.chromeless && (
<div className={cx(styles.topNav)}>
{!searchBarHidden && <TopSearchBar />}
<NavToolbar
searchBarHidden={searchBarHidden}
sectionNav={state.sectionNav}
pageNav={state.pageNav}
actions={state.actions}
onToggleSearchBar={chrome.onToggleSearchBar}
onToggleMegaMenu={chrome.onToggleMegaMenu}
onToggleKioskMode={chrome.onToggleKioskMode}
/>
</div>
)}
<div className={cx(styles.topNav)}>
{!searchBarHidden && <TopSearchBar />}
<NavToolbar
searchBarHidden={searchBarHidden}
sectionNav={state.sectionNav}
pageNav={state.pageNav}
actions={state.actions}
onToggleSearchBar={chrome.onToggleSearchBar}
onToggleMegaMenu={chrome.onToggleMegaMenu}
onToggleKioskMode={chrome.onToggleKioskMode}
/>
</div>
<div className={contentClass}>{children}</div>
{!state.chromeless && <MegaMenu searchBarHidden={searchBarHidden} onClose={() => chrome.setMegaMenu(false)} />}
<MegaMenu searchBarHidden={searchBarHidden} onClose={() => chrome.setMegaMenu(false)} />
{featureToggles.commandPalette && <CommandPalette />}
{!featureToggles.topNavCommandPalette && <SearchWrapper />}
</main>
);
}

@ -1,9 +1,8 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { config } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
import { NavLandingPage } from './NavLandingPage';
@ -51,11 +50,10 @@ describe('NavLandingPage', () => {
},
];
const store = configureStore();
return render(
<Provider store={store}>
<TestProvider>
<NavLandingPage navId={mockId} />
</Provider>
</TestProvider>
);
};

@ -1,11 +1,10 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { OrgRole } from '@grafana/data';
import { ContextSrv, setContextSrv } from 'app/core/services/context_srv';
import { getUserOrganizations } from 'app/features/org/state/actions';
import { configureStore } from 'app/store/configureStore';
import * as appTypes from 'app/types';
import { OrganizationSwitcher } from './OrganizationSwitcher';
@ -22,12 +21,10 @@ jest.mock('app/types', () => ({
}));
const renderWithProvider = ({ initialState }: { initialState?: Partial<appTypes.StoreState> }) => {
const store = configureStore(initialState);
render(
<Provider store={store}>
<TestProvider storeState={initialState}>
<OrganizationSwitcher />
</Provider>
</TestProvider>
);
};

@ -1,11 +1,10 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { NavModelItem, NavSection } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
import { QuickAdd } from './QuickAdd';
@ -37,12 +36,10 @@ const setup = () => {
},
];
const store = configureStore({ navBarTree });
return render(
<Provider store={store}>
<TestProvider storeState={{ navBarTree }}>
<QuickAdd />
</Provider>
</TestProvider>
);
};

@ -1,15 +1,12 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
import { NavModelItem, NavSection } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
import { configureStore } from 'app/store/configureStore';
import TestProvider from '../../../../test/helpers/TestProvider';
import { TestProvider } from '../../../../test/helpers/TestProvider';
import { MegaMenu } from './MegaMenu';
@ -33,21 +30,15 @@ const setup = () => {
},
];
const context = getGrafanaContextMock();
const store = configureStore({ navBarTree });
context.chrome.onToggleMegaMenu();
const grafanaContext = getGrafanaContextMock();
grafanaContext.chrome.onToggleMegaMenu();
return render(
<Provider store={store}>
<GrafanaContext.Provider value={context}>
<TestProvider>
<Router history={locationService.getHistory()}>
<MegaMenu onClose={() => {}} />
</Router>
</TestProvider>
</GrafanaContext.Provider>
</Provider>
<TestProvider storeState={{ navBarTree }} grafanaContext={grafanaContext}>
<Router history={locationService.getHistory()}>
<MegaMenu onClose={() => {}} />
</Router>
</TestProvider>
);
};

@ -1,12 +1,9 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { locationService } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
import TestProvider from '../../../../test/helpers/TestProvider';
import { TestProvider } from '../../../../test/helpers/TestProvider';
import { NavBar } from './NavBar';
@ -22,16 +19,10 @@ jest.mock('app/core/services/context_srv', () => ({
}));
const setup = () => {
const store = configureStore();
return render(
<Provider store={store}>
<TestProvider>
<Router history={locationService.getHistory()}>
<NavBar />
</Router>
</TestProvider>
</Provider>
<TestProvider>
<NavBar />
</TestProvider>
);
};

@ -192,10 +192,6 @@ const getStyles = (theme: GrafanaTheme2) => ({
navWrapper: css({
position: 'relative',
display: 'flex',
'.sidemenu-hidden &': {
display: 'none',
},
}),
sidemenu: css({
label: 'sidemenu',

@ -6,8 +6,6 @@ import { BrowserRouter } from 'react-router-dom';
import { locationUtil } from '@grafana/data';
import { config, setLocationService } from '@grafana/runtime';
import TestProvider from '../../../../test/helpers/TestProvider';
// Need to mock createBrowserHistory here to avoid errors
jest.mock('history', () => ({
...jest.requireActual('history'),
@ -45,18 +43,16 @@ async function getTestContext(overrides: Partial<Props> = {}, subUrl = '', isMen
const props = { ...defaults, ...overrides };
const { rerender } = render(
<TestProvider>
<BrowserRouter>
<NavBarContext.Provider
value={{
menuIdOpen: isMenuOpen ? props.link.id : undefined,
setMenuIdOpen: setMenuIdOpenMock,
}}
>
<NavBarItem {...props} />
</NavBarContext.Provider>
</BrowserRouter>
</TestProvider>
<BrowserRouter>
<NavBarContext.Provider
value={{
menuIdOpen: isMenuOpen ? props.link.id : undefined,
setMenuIdOpen: setMenuIdOpenMock,
}}
>
<NavBarItem {...props} />
</NavBarContext.Provider>
</BrowserRouter>
);
// Need to click this first to set the correct selection range

@ -1,10 +1,9 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { NavModelItem } from '@grafana/data';
import { config } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
import { Page } from './Page';
import { PageProps } from './types';
@ -30,14 +29,12 @@ const setup = (props: Partial<PageProps>) => {
},
];
const store = configureStore();
return render(
<Provider store={store}>
<TestProvider>
<Page {...props}>
<div data-testid="page-children">Children</div>
</Page>
</Provider>
</TestProvider>
);
};

@ -1,10 +1,11 @@
// Libraries
import { css, cx } from '@emotion/css';
import React from 'react';
import React, { useEffect } from 'react';
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
import { config } from '@grafana/runtime';
import { CustomScrollbar, useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { Footer } from '../Footer/Footer';
import { PageHeader } from '../PageHeader/PageHeader';
@ -34,11 +35,21 @@ export const OldPage: PageType = ({
}) => {
const styles = useStyles2(getStyles);
const navModel = usePageNav(navId, oldNavProp);
const { chrome } = useGrafana();
usePageTitle(navModel, pageNav);
const pageHeaderNav = pageNav ?? navModel?.main;
useEffect(() => {
if (navModel) {
// This is needed for chrome to update it's chromeless state
chrome.update({
sectionNav: navModel.node,
});
}
}, [navModel, chrome]);
return (
<div className={cx(styles.wrapper, className)} {...otherProps}>
{layout === PageLayoutType.Standard && (

@ -1,13 +1,11 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
import { NavModelItem } from '@grafana/data';
import { config } from '@grafana/runtime';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
import { HOME_NAV_ID } from 'app/core/reducers/navModel';
import { configureStore } from 'app/store/configureStore';
import { PageProps } from '../Page/types';
@ -38,16 +36,13 @@ const setup = (props: Partial<PageProps>) => {
];
const context = getGrafanaContextMock();
const store = configureStore();
const renderResult = render(
<Provider store={store}>
<GrafanaContext.Provider value={context}>
<Page {...props}>
<div data-testid="page-children">Children</div>
</Page>
</GrafanaContext.Provider>
</Provider>
<TestProvider grafanaContext={context}>
<Page {...props}>
<div data-testid="page-children">Children</div>
</Page>
</TestProvider>
);
return { renderResult, context };

@ -1,7 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import TestProvider from 'test/helpers/TestProvider';
import { assertInstanceOf } from 'test/helpers/asserts';
import { getSelectParent, selectOptionInTest } from 'test/helpers/selectOptionInTest';
@ -124,11 +123,7 @@ describe('SharedPreferences', () => {
mockReload.mockReset();
mockPrefsUpdate.mockReset();
render(
<TestProvider>
<SharedPreferences {...props} />
</TestProvider>
);
render(<SharedPreferences {...props} />);
await waitFor(() => expect(mockPrefsLoad).toHaveBeenCalled());
});

@ -1,19 +1,14 @@
import { render, screen } from '@testing-library/react';
import React, { ComponentType } from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
import { TestProvider } from 'test/helpers/TestProvider';
import { setEchoSrv } from '@grafana/runtime';
import { configureStore } from '../../store/configureStore';
import { GrafanaContext } from '../context/GrafanaContext';
import { Echo } from '../services/echo/Echo';
import { GrafanaRoute, Props } from './GrafanaRoute';
function setup(overrides: Partial<Props>) {
const store = configureStore();
const props: Props = {
location: { search: '?query=hello&test=asd' } as any,
history: {} as any,
@ -26,13 +21,9 @@ function setup(overrides: Partial<Props>) {
};
render(
<BrowserRouter>
<GrafanaContext.Provider value={getGrafanaContextMock()}>
<Provider store={store}>
<GrafanaRoute {...props} />
</Provider>
</GrafanaContext.Provider>
</BrowserRouter>
<TestProvider>
<GrafanaRoute {...props} />
</TestProvider>
);
}

@ -19,8 +19,8 @@ export function GrafanaRoute(props: Props) {
chrome.setMatchedRoute(props.route);
useLayoutEffect(() => {
keybindings.clearAndInitGlobalBindings();
}, [keybindings]);
keybindings.clearAndInitGlobalBindings(props.route);
}, [keybindings, props.route]);
useEffect(() => {
updateBodyClassNames(props.route);

@ -23,6 +23,7 @@ import {
import { AppChromeService } from '../components/AppChrome/AppChromeService';
import { HelpModal } from '../components/help/HelpModal';
import { contextSrv } from '../core';
import { RouteDescriptor } from '../navigation/types';
import { toggleTheme } from './theme';
import { withFocusedPanel } from './withFocusedPanelId';
@ -30,10 +31,11 @@ import { withFocusedPanel } from './withFocusedPanelId';
export class KeybindingSrv {
constructor(private locationService: LocationService, private chromeService: AppChromeService) {}
clearAndInitGlobalBindings() {
clearAndInitGlobalBindings(route: RouteDescriptor) {
Mousetrap.reset();
if (this.locationService.getLocation().pathname !== '/login') {
// Chromeless pages like login and signup page don't get any global bindings
if (!route.chromeless) {
this.bind(['?', 'h'], this.showHelpModal);
this.bind('g h', this.goToHome);
this.bind('g a', this.openAlerting);

@ -1,15 +1,14 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { openMenu } from 'react-select-event';
import { mockToolkitActionCreator } from 'test/core/redux/mocks';
import { TestProvider } from 'test/helpers/TestProvider';
import { locationService } from '@grafana/runtime';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
import appEvents from '../../core/app_events';
import { configureStore } from '../../store/configureStore';
import { ShowModalReactEvent } from '../../types/events';
import { AlertHowToModal } from './AlertHowToModal';
@ -31,20 +30,19 @@ const defaultProps: Props = {
};
const setup = (propOverrides?: object) => {
const store = configureStore();
const props: Props = {
...defaultProps,
...propOverrides,
};
const { rerender } = render(
<Provider store={store}>
<TestProvider>
<AlertRuleListUnconnected {...props} />
</Provider>
</TestProvider>
);
return {
rerender: (element: JSX.Element) => rerender(<Provider store={store}>{element}</Provider>),
rerender: (element: JSX.Element) => rerender(<TestProvider>{element}</TestProvider>),
};
};

@ -1,12 +1,10 @@
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId, byText } from 'testing-library-selector';
import { locationService, setDataSourceSrv } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
import { setDataSourceSrv } from '@grafana/runtime';
import AlertGroups from './AlertGroups';
import { fetchAlertGroups } from './api/alertmanager';
@ -28,14 +26,10 @@ const mocks = {
};
const renderAmNotifications = () => {
const store = configureStore();
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<AlertGroups />
</Router>
</Provider>
<TestProvider>
<AlertGroups />
</TestProvider>
);
};

@ -1,11 +1,9 @@
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byTestId } from 'testing-library-selector';
import { configureStore } from 'app/store/configureStore';
import { FolderState } from 'app/types';
import { CombinedRuleNamespace } from 'app/types/unified-alerting';
@ -47,7 +45,6 @@ const mockFolder = (folderOverride: Partial<FolderState> = {}): FolderState => {
describe('AlertsFolderView tests', () => {
it('Should display grafana alert rules when the namespace name matches the folder name', () => {
// Arrange
const store = configureStore();
const folder = mockFolder();
const grafanaNamespace: CombinedRuleNamespace = {
@ -77,11 +74,9 @@ describe('AlertsFolderView tests', () => {
// Act
render(
<Provider store={store}>
<MemoryRouter>
<AlertsFolderView folder={folder} />
</MemoryRouter>
</Provider>
<TestProvider>
<AlertsFolderView folder={folder} />
</TestProvider>
);
// Assert
@ -97,7 +92,6 @@ describe('AlertsFolderView tests', () => {
it('Should not display alert rules when the namespace name does not match the folder name', () => {
// Arrange
const store = configureStore();
const folder = mockFolder();
const grafanaNamespace: CombinedRuleNamespace = {
@ -118,11 +112,9 @@ describe('AlertsFolderView tests', () => {
// Act
render(
<Provider store={store}>
<MemoryRouter>
<AlertsFolderView folder={folder} />
</MemoryRouter>
</Provider>
<TestProvider>
<AlertsFolderView folder={folder} />
</TestProvider>
);
// Assert
@ -131,7 +123,6 @@ describe('AlertsFolderView tests', () => {
it('Should filter alert rules by the name, case insensitive', async () => {
// Arrange
const store = configureStore();
const folder = mockFolder();
const grafanaNamespace: CombinedRuleNamespace = {
@ -149,11 +140,9 @@ describe('AlertsFolderView tests', () => {
// Act
render(
<Provider store={store}>
<MemoryRouter>
<AlertsFolderView folder={folder} />
</MemoryRouter>
</Provider>
<TestProvider>
<AlertsFolderView folder={folder} />
</TestProvider>
);
await userEvent.type(ui.filter.name.get(), 'cpu');
@ -165,7 +154,6 @@ describe('AlertsFolderView tests', () => {
it('Should filter alert rule by labels', async () => {
// Arrange
const store = configureStore();
const folder = mockFolder();
const grafanaNamespace: CombinedRuleNamespace = {
@ -186,11 +174,9 @@ describe('AlertsFolderView tests', () => {
// Act
render(
<Provider store={store}>
<MemoryRouter>
<AlertsFolderView folder={folder} />
</MemoryRouter>
</Provider>
<TestProvider>
<AlertsFolderView folder={folder} />
</TestProvider>
);
await userEvent.type(ui.filter.label.get(), 'severity=critical');

@ -1,8 +1,7 @@
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { byLabelText, byRole, byTestId, byText } from 'testing-library-selector';
@ -15,7 +14,6 @@ import {
MuteTimeInterval,
Route,
} from 'app/plugins/datasource/alertmanager/types';
import { configureStore } from 'app/store/configureStore';
import { AccessControlAction } from 'app/types';
import AmRoutes from './AmRoutes';
@ -47,19 +45,15 @@ const mocks = {
const useGetGrafanaReceiverTypeCheckerMock = jest.spyOn(grafanaApp, 'useGetGrafanaReceiverTypeChecker');
const renderAmRoutes = (alertManagerSourceName?: string) => {
const store = configureStore();
locationService.push(location);
locationService.push(
'/alerting/routes' + (alertManagerSourceName ? `?${ALERTMANAGER_NAME_QUERY_KEY}=${alertManagerSourceName}` : '')
);
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<AmRoutes />
</Router>
</Provider>
<TestProvider>
<AmRoutes />
</TestProvider>
);
};

@ -2,8 +2,7 @@ import { render, waitFor, waitForElementToBeRemoved } from '@testing-library/rea
import { setupServer } from 'msw/node';
import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId, byText } from 'testing-library-selector';
import { selectors } from '@grafana/e2e-selectors/src';
@ -91,11 +90,9 @@ function getProvidersWrapper() {
const formApi = useForm<RuleFormValues>({ defaultValues: getDefaultFormValues() });
return (
<MemoryRouter>
<Provider store={store}>
<FormProvider {...formApi}>{children}</FormProvider>
</Provider>
</MemoryRouter>
<TestProvider store={store}>
<FormProvider {...formApi}>{children}</FormProvider>
</TestProvider>
);
};
}

@ -1,13 +1,11 @@
import { render, waitFor, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId, byText } from 'testing-library-selector';
import { locationService, setDataSourceSrv } from '@grafana/runtime';
import { AlertManagerCortexConfig, MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types';
import { configureStore } from 'app/store/configureStore';
import MuteTimings from './MuteTimings';
import { fetchAlertManagerConfig, updateAlertManagerConfig } from './api/alertmanager';
@ -24,15 +22,12 @@ const mocks = {
};
const renderMuteTimings = (location = '/alerting/routes/mute-timing/new') => {
const store = configureStore();
locationService.push(location);
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<MuteTimings />
</Router>
</Provider>
<TestProvider>
<MuteTimings />
</TestProvider>
);
};

@ -1,11 +1,10 @@
import { render, act, waitFor } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byTestId } from 'testing-library-selector';
import { DataSourceApi } from '@grafana/data';
import { locationService, setDataSourceSrv } from '@grafana/runtime';
import { setDataSourceSrv } from '@grafana/runtime';
import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
@ -69,15 +68,11 @@ const renderAlertTabContent = (
panel: PanelModel,
initialStore?: ReturnType<typeof configureStore>
) => {
const store = initialStore ?? configureStore();
return act(async () => {
render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<PanelAlertTabContent dashboard={dashboard} panel={panel} />
</Router>
</Provider>
<TestProvider store={initialStore}>
<PanelAlertTabContent dashboard={dashboard} panel={panel} />
</TestProvider>
);
});
};

@ -2,8 +2,7 @@ import { render, waitFor, within, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { setupServer } from 'msw/node';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { byLabelText, byPlaceholderText, byRole, byTestId, byText } from 'testing-library-selector';
@ -17,7 +16,6 @@ import {
AlertManagerDataSourceJsonData,
AlertManagerImplementation,
} from 'app/plugins/datasource/alertmanager/types';
import { configureStore } from 'app/store/configureStore';
import { AccessControlAction, ContactPointsState } from 'app/types';
import 'whatwg-fetch';
@ -70,19 +68,15 @@ const alertmanagerChoiceMockedResponse: AlertmanagersChoiceResponse = {
};
const renderReceivers = (alertManagerSourceName?: string) => {
const store = configureStore();
locationService.push(
'/alerting/notifications' +
(alertManagerSourceName ? `?${ALERTMANAGER_NAME_QUERY_KEY}=${alertManagerSourceName}` : '')
);
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<Receivers />
</Router>
</Provider>
<TestProvider>
<Receivers />
</TestProvider>
);
};

@ -1,11 +1,10 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { useLocation } from 'react-use';
import { TestProvider } from 'test/helpers/TestProvider';
import { DataSourceJsonData, PluginMeta } from '@grafana/data';
import { configureStore } from 'app/store/configureStore';
import { locationService } from '@grafana/runtime';
import { CombinedRule, Rule } from '../../../types/unified-alerting';
import { PromRuleType } from '../../../types/unified-alerting-dto';
@ -24,16 +23,15 @@ jest.mock('react-router-dom', () => ({
jest.mock('react-use');
const store = configureStore();
const renderRedirectToRuleViewer = (pathname: string) => {
jest.mocked(useLocation).mockReturnValue({ pathname, trigger: '' });
locationService.push(pathname);
return render(
<Provider store={store}>
<MemoryRouter initialEntries={[pathname]}>
<RedirectToRuleViewer />
</MemoryRouter>
</Provider>
<TestProvider>
<RedirectToRuleViewer />
</TestProvider>
);
};

@ -1,8 +1,8 @@
import { render, waitFor, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { Route, Router } from 'react-router-dom';
import { Route } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { ui } from 'test/helpers/alertingRuleEditor';
import { clickSelectOptionMatch } from 'test/helpers/selectOptionInTest';
import { byRole } from 'testing-library-selector';
@ -11,7 +11,6 @@ import { locationService, setDataSourceSrv } from '@grafana/runtime';
import { ADD_NEW_FOLER_OPTION } from 'app/core/components/Select/FolderPicker';
import { contextSrv } from 'app/core/services/context_srv';
import { DashboardSearchHit } from 'app/features/search/types';
import { configureStore } from 'app/store/configureStore';
import { GrafanaAlertStateDecision } from 'app/types/unified-alerting-dto';
import { searchFolders } from '../../../../app/features/manage-dashboards/state/actions';
@ -64,16 +63,12 @@ const mocks = {
};
function renderRuleEditor(identifier?: string) {
const store = configureStore();
locationService.push(identifier ? `/alerting/${identifier}/edit` : `/alerting/new`);
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<Route path={['/alerting/new', '/alerting/:id/edit']} component={RuleEditor} />
</Router>
</Provider>
<TestProvider>
<Route path={['/alerting/new', '/alerting/:id/edit']} component={RuleEditor} />
</TestProvider>
);
}

@ -2,8 +2,7 @@ import { SerializedError } from '@reduxjs/toolkit';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId, byText } from 'testing-library-selector';
import { locationService, logInfo, setBackendSrv, setDataSourceSrv } from '@grafana/runtime';
@ -11,7 +10,6 @@ import { backendSrv } from 'app/core/services/backend_srv';
import { contextSrv } from 'app/core/services/context_srv';
import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
import * as actions from 'app/features/alerting/unified/state/actions';
import { configureStore } from 'app/store/configureStore';
import { AccessControlAction } from 'app/types';
import { PromAlertingRuleState, PromApplication } from 'app/types/unified-alerting-dto';
@ -76,15 +74,12 @@ const mocks = {
};
const renderRuleList = () => {
const store = configureStore();
locationService.push('/');
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<RuleList />
</Router>
</Provider>
<TestProvider>
<RuleList />
</TestProvider>
);
};

@ -1,14 +1,12 @@
import { act, render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole } from 'testing-library-selector';
import { locationService, setBackendSrv } from '@grafana/runtime';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { backendSrv } from 'app/core/services/backend_srv';
import { contextSrv } from 'app/core/services/context_srv';
import { configureStore } from 'app/store/configureStore';
import { AccessControlAction } from 'app/types';
import { CombinedRule } from 'app/types/unified-alerting';
@ -45,15 +43,12 @@ jest.mock('@grafana/runtime', () => ({
},
}));
const store = configureStore();
const renderRuleViewer = () => {
return act(async () => {
render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<RuleViewer {...mockRoute} />
</Router>
</Provider>
<TestProvider>
<RuleViewer {...mockRoute} />
</TestProvider>
);
});
};

@ -1,15 +1,13 @@
import { render, waitFor } from '@testing-library/react';
import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byLabelText, byPlaceholderText, byRole, byTestId, byText } from 'testing-library-selector';
import { dateTime } from '@grafana/data';
import { locationService, setDataSourceSrv, config } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
import { AlertState, MatcherOperator } from 'app/plugins/datasource/alertmanager/types';
import { configureStore } from 'app/store/configureStore';
import { AccessControlAction } from 'app/types';
import Silences from './Silences';
@ -33,15 +31,12 @@ const mocks = {
};
const renderSilences = (location = '/alerting/silences/') => {
const store = configureStore();
locationService.push(location);
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<Silences />
</Router>
</Provider>
<TestProvider>
<Silences />
</TestProvider>
);
};

@ -1,8 +1,7 @@
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { byLabelText, byRole, byTestId } from 'testing-library-selector';
import { locationService, setDataSourceSrv } from '@grafana/runtime';
@ -13,7 +12,6 @@ import {
AlertManagerDataSourceJsonData,
AlertManagerImplementation,
} from 'app/plugins/datasource/alertmanager/types';
import { configureStore } from 'app/store/configureStore';
import {
fetchAlertManagerConfig,
@ -50,19 +48,15 @@ const mocks = {
};
const renderAdminPage = (alertManagerSourceName?: string) => {
const store = configureStore();
locationService.push(
'/alerting/notifications' +
(alertManagerSourceName ? `?${ALERTMANAGER_NAME_QUERY_KEY}=${alertManagerSourceName}` : '')
);
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<AlertmanagerConfig />
</Router>
</Provider>
<TestProvider>
<AlertmanagerConfig />
</TestProvider>
);
};

@ -1,9 +1,7 @@
import { screen, render, within } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { locationService } from '@grafana/runtime';
import {
AlertManagerCortexConfig,
GrafanaManagedReceiverConfig,
@ -31,11 +29,9 @@ const renderReceieversTable = async (receivers: Receiver[], notifiers: NotifierD
await store.dispatch(fetchGrafanaNotifiersAction.fulfilled(notifiers, 'initial'));
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<ReceiversTable config={config} alertManagerName="alertmanager-1" />
</Router>
</Provider>
<TestProvider store={store}>
<ReceiversTable config={config} alertManagerName="alertmanager-1" />
</TestProvider>
);
};

@ -4,7 +4,7 @@ import { rest } from 'msw';
import { setupServer } from 'msw/node';
import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId } from 'testing-library-selector';
import { setBackendSrv } from '@grafana/runtime';
@ -63,11 +63,11 @@ function FormWrapper({ formValues }: { formValues?: Partial<RuleFormValues> }) {
const formApi = useForm<RuleFormValues>({ defaultValues: { ...getDefaultFormValues(), ...formValues } });
return (
<Provider store={store}>
<TestProvider store={store}>
<FormProvider {...formApi}>
<AnnotationsField />
</FormProvider>
</Provider>
</TestProvider>
);
}

@ -1,14 +1,13 @@
import { render, screen, within } from '@testing-library/react';
import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
import { ApiKey, OrgRole } from 'app/types';
import { mockToolkitActionCreator } from '../../../test/core/redux/mocks';
import { silenceConsoleOutput } from '../../../test/core/utils/silenceConsoleOutput';
import { configureStore } from '../../store/configureStore';
import { ApiKeysPageUnconnected, Props } from './ApiKeysPage';
import { getMultipleMockKeys } from './__mocks__/apiKeysMock';
@ -24,7 +23,6 @@ jest.mock('app/core/core', () => {
});
const setup = (propOverrides: Partial<Props>) => {
const store = configureStore();
const loadApiKeysMock = jest.fn();
const deleteApiKeyMock = jest.fn();
const migrateApiKeyMock = jest.fn();
@ -58,12 +56,12 @@ const setup = (propOverrides: Partial<Props>) => {
Object.assign(props, propOverrides);
const { rerender } = render(
<Provider store={store}>
<TestProvider>
<ApiKeysPageUnconnected {...props} />
</Provider>
</TestProvider>
);
return {
rerender: (element: JSX.Element) => rerender(<Provider store={store}>{element}</Provider>),
rerender: (element: JSX.Element) => rerender(<TestProvider>{element}</TestProvider>),
props,
loadApiKeysMock,
setSearchQueryMock,

@ -26,7 +26,7 @@ import useActions from './actions/useActions';
import { CommandPaletteAction } from './types';
import { useMatches } from './useMatches';
export const CommandPalette = () => {
export function CommandPalette() {
const styles = useStyles2(getSearchStyles);
const { query, showing, searchQuery } = useKBar((state) => ({
@ -43,6 +43,7 @@ export const CommandPalette = () => {
{ isOpen: showing, onClose: () => query.setVisualState(VisualState.animatingOut) },
ref
);
const { dialogProps } = useDialog({}, ref);
// Report interaction when opened
@ -72,7 +73,7 @@ export const CommandPalette = () => {
</KBarPositioner>
</KBarPortal>
) : null;
};
}
interface RenderResultsProps {
dashboardResults: CommandPaletteAction[];

@ -1,7 +1,6 @@
import { render, RenderResult, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { locationService } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
@ -25,11 +24,9 @@ const renderPage = (
locationService.push(path);
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<Connections />
</Router>
</Provider>
<TestProvider store={store}>
<Connections />
</TestProvider>
);
};
@ -86,6 +83,7 @@ describe('Connections', () => {
url: '/connections/connect-data',
pluginId: 'grafana-easystart-app',
};
const connections = {
...navIndex.connections,
children: navIndex.connections.children?.map((child) => {
@ -96,6 +94,7 @@ describe('Connections', () => {
return child;
}),
};
const store = configureStore({
navIndex: { ...navIndex, connections, [standalonePluginPage.id]: standalonePluginPage },
plugins: getPluginsStateMock([]),

@ -11,8 +11,8 @@ import {
import { merge, uniqueId } from 'lodash';
import React from 'react';
import { DeepPartial } from 'react-hook-form';
import { Provider } from 'react-redux';
import { Observable } from 'rxjs';
import { TestProvider } from 'test/helpers/TestProvider';
import { MockDataSourceApi } from 'test/mocks/datasource_srv';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
@ -25,7 +25,6 @@ import {
BackendSrvRequest,
reportInteraction,
} from '@grafana/runtime';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
import { contextSrv } from 'app/core/services/context_srv';
import { configureStore } from 'app/store/configureStore';
@ -150,11 +149,9 @@ const renderWithContext = async (
setDataSourceSrv(dsServer);
const renderResult = render(
<Provider store={configureStore({})}>
<GrafanaContext.Provider value={grafanaContext}>
<CorrelationsPage />
</GrafanaContext.Provider>
</Provider>,
<TestProvider store={configureStore({})} grafanaContext={grafanaContext}>
<CorrelationsPage />
</TestProvider>,
{
queries: {
/**

@ -2,23 +2,18 @@ import { within } from '@testing-library/dom';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
import { locationService, setAngularLoader, setDataSourceSrv } from '@grafana/runtime';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified/mocks';
import { configureStore } from '../../../../store/configureStore';
import { DashboardModel } from '../../state/DashboardModel';
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
import { AnnotationsSettings } from './AnnotationsSettings';
function setup(dashboard: DashboardModel, editIndex?: number) {
const store = configureStore();
const sectionNav = {
main: { text: 'Dashboard' },
node: {
@ -27,13 +22,9 @@ function setup(dashboard: DashboardModel, editIndex?: number) {
};
return render(
<GrafanaContext.Provider value={getGrafanaContextMock()}>
<Provider store={store}>
<BrowserRouter>
<AnnotationsSettings sectionNav={sectionNav} dashboard={dashboard} editIndex={editIndex} />
</BrowserRouter>
</Provider>
</GrafanaContext.Provider>
<TestProvider>
<AnnotationsSettings sectionNav={sectionNav} dashboard={dashboard} editIndex={editIndex} />
</TestProvider>
);
}

@ -1,26 +1,14 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
import { TestProvider } from 'test/helpers/TestProvider';
import { NavModel, NavModelItem } from '@grafana/data';
import { BackendSrv, setBackendSrv } from '@grafana/runtime';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
import { configureStore } from 'app/store/configureStore';
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
import { DashboardSettings } from './DashboardSettings';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
locationService: {
getSearchObject: jest.fn().mockResolvedValue({}),
partial: jest.fn(),
},
}));
setBackendSrv({
get: jest.fn().mockResolvedValue([]),
} as unknown as BackendSrv);
@ -36,19 +24,13 @@ describe('DashboardSettings', () => {
}
);
const store = configureStore();
const context = getGrafanaContextMock();
const sectionNav: NavModel = { main: { text: 'Dashboards' }, node: { text: 'Dashboards' } };
const pageNav: NavModelItem = { text: 'My cool dashboard' };
render(
<GrafanaContext.Provider value={context}>
<Provider store={store}>
<BrowserRouter>
<DashboardSettings editview="settings" dashboard={dashboard} sectionNav={sectionNav} pageNav={pageNav} />
</BrowserRouter>
</Provider>
</GrafanaContext.Provider>
<TestProvider>
<DashboardSettings editview="settings" dashboard={dashboard} sectionNav={sectionNav} pageNav={pageNav} />
</TestProvider>
);
expect(await screen.findByRole('tab', { name: 'Tab Settings' })).toBeInTheDocument();

@ -3,13 +3,12 @@ import { rest } from 'msw';
import { setupServer } from 'msw/node';
import React from 'react';
import { DeepPartial } from 'react-hook-form';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { DataSourcePluginMeta } from '@grafana/data';
import * as runtime from '@grafana/runtime';
import { backendSrv } from 'app/core/services/backend_srv';
import { contextSrv } from 'app/core/services/context_srv';
import { configureStore } from 'app/store/configureStore';
import 'whatwg-fetch';
import { EmptyStateNoDatasource } from './EmptyStateNoDatasource';
@ -60,9 +59,9 @@ describe('EmptyStateNoDatasource', () => {
})
);
render(
<Provider store={configureStore()}>
<TestProvider>
<EmptyStateNoDatasource title="A Title" CTAText="CTA" />
</Provider>
</TestProvider>
);
await waitFor(() => {

@ -1,7 +1,7 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Store } from 'redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { setAngularLoader } from '@grafana/runtime';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
@ -23,7 +23,7 @@ jest.mock('app/core/services/context_srv', () => ({
const setup = (uid: string, store: Store) =>
render(
<Provider store={store}>
<TestProvider store={store}>
<DataSourceDashboardsPage
{...getRouteComponentProps({
// @ts-ignore
@ -34,7 +34,7 @@ const setup = (uid: string, store: Store) =>
},
})}
/>
</Provider>
</TestProvider>
);
describe('<DataSourceDashboardsPage>', () => {

@ -1,10 +1,9 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { LayoutModes } from '@grafana/data';
import { contextSrv } from 'app/core/services/context_srv';
import { configureStore } from 'app/store/configureStore';
import { navIndex, getMockDataSources } from '../__mocks__';
import { getDataSources } from '../api';
@ -21,19 +20,19 @@ jest.mock('../api', () => ({
const getDataSourcesMock = getDataSources as jest.Mock;
const setup = (options: { isSortAscending: boolean }) => {
const store = configureStore({
const storeState = {
dataSources: {
...initialState,
layoutMode: LayoutModes.Grid,
isSortAscending: options.isSortAscending,
},
navIndex,
});
};
return render(
<Provider store={store}>
<TestProvider storeState={storeState}>
<DataSourcesListPage />
</Provider>
</TestProvider>
);
};

@ -1,7 +1,7 @@
import { screen, render } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Store } from 'redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { LayoutModes } from '@grafana/data';
import { setAngularLoader } from '@grafana/runtime';
@ -36,7 +36,7 @@ jest.mock('@grafana/runtime', () => {
const setup = (uid: string, store: Store) =>
render(
<Provider store={store}>
<TestProvider store={store}>
<EditDataSourcePage
{...getRouteComponentProps({
// @ts-ignore
@ -47,7 +47,7 @@ const setup = (uid: string, store: Store) =>
},
})}
/>
</Provider>
</TestProvider>
);
describe('<EditDataSourcePage>', () => {

@ -1,13 +1,12 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { mockToolkitActionCreator } from 'test/core/redux/mocks';
import { TestProvider } from 'test/helpers/TestProvider';
import { NavModel } from '@grafana/data';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
import { ModalManager } from 'app/core/services/ModalManager';
import { configureStore } from 'app/store/configureStore';
import { FolderSettingsPage, Props } from './FolderSettingsPage';
import { setFolderTitle } from './state/reducers';
@ -38,9 +37,9 @@ const setup = (propOverrides?: object) => {
Object.assign(props, propOverrides);
render(
<Provider store={configureStore()}>
<TestProvider>
<FolderSettingsPage {...props} />
</Provider>
</TestProvider>
);
};

@ -1,12 +1,11 @@
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
import { backendSrv } from '../../core/services/backend_srv';
import { configureStore } from '../../store/configureStore';
import { SignupInvitedPage, Props } from './SignupInvited';
@ -30,7 +29,6 @@ const defaultGet = {
async function setupTestContext({ get = defaultGet }: { get?: typeof defaultGet | null } = {}) {
jest.clearAllMocks();
const store = configureStore();
const getSpy = jest.spyOn(backendSrv, 'get');
getSpy.mockResolvedValue(get);
@ -47,9 +45,9 @@ async function setupTestContext({ get = defaultGet }: { get?: typeof defaultGet
};
render(
<Provider store={store}>
<TestProvider>
<SignupInvitedPage {...props} />
</Provider>
</TestProvider>
);
await waitFor(() => expect(getSpy).toHaveBeenCalled());

@ -1,14 +1,13 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { mockToolkitActionCreator } from 'test/core/redux/mocks';
import { TestProvider } from 'test/helpers/TestProvider';
import { NavModel } from '@grafana/data';
import { ModalManager } from 'app/core/services/ModalManager';
import { backendSrv } from '../../core/services/backend_srv';
import { configureStore } from '../../store/configureStore';
import { Organization } from '../../types';
import { OrgDetailsPage, Props } from './OrgDetailsPage';
@ -37,7 +36,6 @@ jest.mock('@grafana/runtime', () => {
});
const setup = (propOverrides?: object) => {
const store = configureStore();
jest.clearAllMocks();
// needed because SharedPreferences is rendered in the test
jest.spyOn(backendSrv, 'put');
@ -63,9 +61,9 @@ const setup = (propOverrides?: object) => {
Object.assign(props, propOverrides);
render(
<Provider store={store}>
<TestProvider>
<OrgDetailsPage {...props} />
</Provider>
</TestProvider>
);
};

@ -1,13 +1,11 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { locationService } from '@grafana/runtime';
import { backendSrv } from 'app/core/services/backend_srv';
import { configureStore } from '../../store/configureStore';
import { PlaylistEditPage } from './PlaylistEditPage';
import { Playlist } from './types';
@ -24,7 +22,6 @@ jest.mock('app/core/components/TagFilter/TagFilter', () => ({
async function getTestContext({ name, interval, items, uid }: Partial<Playlist> = {}) {
jest.clearAllMocks();
const store = configureStore();
const playlist = { name, items, interval, uid } as unknown as Playlist;
const queryParams = {};
const route: any = {};
@ -33,16 +30,18 @@ async function getTestContext({ name, interval, items, uid }: Partial<Playlist>
const history: any = {};
const getMock = jest.spyOn(backendSrv, 'get');
const putMock = jest.spyOn(backendSrv, 'put');
getMock.mockResolvedValue({
name: 'Test Playlist',
interval: '5s',
items: [{ title: 'First item', type: 'dashboard_by_uid', order: 1, value: '1' }],
uid: 'foo',
});
const { rerender } = render(
<Provider store={store}>
<TestProvider>
<PlaylistEditPage queryParams={queryParams} route={route} match={match} location={location} history={history} />
</Provider>
</TestProvider>
);
await waitFor(() => expect(getMock).toHaveBeenCalledTimes(1));

@ -1,13 +1,12 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
import { locationService } from '@grafana/runtime';
import { backendSrv } from '../../core/services/backend_srv';
import { configureStore } from '../../store/configureStore';
import { PlaylistNewPage } from './PlaylistNewPage';
import { Playlist } from './types';
@ -24,15 +23,14 @@ jest.mock('app/core/components/TagFilter/TagFilter', () => ({
}));
function getTestContext({ name, interval, items }: Partial<Playlist> = {}) {
const store = configureStore();
jest.clearAllMocks();
const playlist = { name, items, interval } as unknown as Playlist;
const backendSrvMock = jest.spyOn(backendSrv, 'post');
const { rerender } = render(
<Provider store={store}>
<TestProvider>
<PlaylistNewPage />
</Provider>
</TestProvider>
);
return { playlist, rerender, backendSrvMock };

@ -1,11 +1,9 @@
import { render, waitFor } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { contextSrv } from 'app/core/services/context_srv';
import { configureStore } from '../../store/configureStore';
import { PlaylistPage } from './PlaylistPage';
const fnMock = jest.fn();
@ -24,11 +22,10 @@ jest.mock('app/core/services/context_srv', () => ({
}));
function getTestContext() {
const store = configureStore();
return render(
<Provider store={store}>
<TestProvider>
<PlaylistPage />
</Provider>
</TestProvider>
);
}

@ -1,8 +1,7 @@
import { render, RenderResult, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { PluginType, escapeStringForRegex } from '@grafana/data';
import { locationService } from '@grafana/runtime';
@ -37,11 +36,9 @@ const renderBrowse = (
});
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<BrowsePage {...props} />
</Router>
</Provider>
<TestProvider store={store}>
<BrowsePage {...props} />
</TestProvider>
);
};

@ -1,8 +1,8 @@
import { getDefaultNormalizer, render, RenderResult, SelectorMatcherOptions, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { MemoryRouter, Route } from 'react-router-dom';
import { Route } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import {
PluginErrorCode,
@ -12,7 +12,7 @@ import {
WithAccessControlMetadata,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
import { config, locationService } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
import { mockPluginApis, getCatalogPluginMock, getPluginsStateMock, mockUserPermissions } from '../__mocks__';
@ -73,12 +73,12 @@ const renderPluginDetails = (
plugins: pluginsStateOverride || getPluginsStateMock([plugin]),
});
locationService.push({ pathname: `/plugins/${id}`, search: pageId ? `?page=${pageId}` : '' });
return render(
<MemoryRouter initialEntries={[{ pathname: `/plugins/${id}`, search: pageId ? `?page=${pageId}` : '' }]}>
<Provider store={store}>
<Route path="/plugins/:pluginId" component={PluginDetailsPage} />
</Provider>
</MemoryRouter>
<TestProvider store={store}>
<Route path="/plugins/:pluginId" component={PluginDetailsPage} />
</TestProvider>
);
};

@ -1,12 +1,11 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import config from 'app/core/config';
import { backendSrv } from '../../core/services/backend_srv';
import { configureStore } from '../../store/configureStore';
import { Props, ChangePasswordPage } from './ChangePasswordPage';
import { initialUserState } from './state/reducers';
@ -28,7 +27,6 @@ const defaultProps: Props = {
};
async function getTestContext(overrides: Partial<Props> = {}) {
const store = configureStore();
jest.clearAllMocks();
jest.spyOn(backendSrv, 'get').mockResolvedValue({
id: 1,
@ -42,9 +40,9 @@ async function getTestContext(overrides: Partial<Props> = {}) {
const props = { ...defaultProps, ...overrides };
const { rerender } = render(
<Provider store={store}>
<TestProvider>
<ChangePasswordPage {...props} />
</Provider>
</TestProvider>
);
await waitFor(() => expect(props.loadUser).toHaveBeenCalledTimes(1));

@ -2,14 +2,12 @@ import { within } from '@testing-library/dom';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { OrgRole } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import TestProvider from '../../../test/helpers/TestProvider';
import { TestProvider } from '../../../test/helpers/TestProvider';
import { backendSrv } from '../../core/services/backend_srv';
import { configureStore } from '../../store/configureStore';
import { TeamPermissionLevel } from '../../types';
import { getMockTeam } from '../teams/__mocks__/teamMocks';
@ -98,7 +96,6 @@ function getSelectors() {
}
async function getTestContext(overrides: Partial<Props> = {}) {
const store = configureStore();
jest.clearAllMocks();
const putSpy = jest.spyOn(backendSrv, 'put');
const getSpy = jest
@ -108,11 +105,9 @@ async function getTestContext(overrides: Partial<Props> = {}) {
const props = { ...defaultProps, ...overrides };
const { rerender } = render(
<Provider store={store}>
<TestProvider>
<UserProfileEditPage {...props} />
</TestProvider>
</Provider>
<TestProvider>
<UserProfileEditPage {...props} />
</TestProvider>
);
await waitFor(() => expect(props.initUserProfilePage).toHaveBeenCalledTimes(1));

@ -1,9 +1,7 @@
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { configureStore } from '../../store/configureStore';
import { TestProvider } from 'test/helpers/TestProvider';
import { ServiceAccountCreatePage, Props } from './ServiceAccountCreatePage';
@ -45,7 +43,6 @@ jest.mock('app/core/core', () => ({
}));
const setup = (propOverrides: Partial<Props>) => {
const store = configureStore();
const props: Props = {
navModel: {
main: {
@ -60,9 +57,9 @@ const setup = (propOverrides: Partial<Props>) => {
Object.assign(props, propOverrides);
render(
<Provider store={store}>
<TestProvider>
<ServiceAccountCreatePage {...props} />
</Provider>
</TestProvider>
);
};

@ -1,12 +1,10 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { ApiKey, OrgRole, ServiceAccountDTO } from 'app/types';
import { configureStore } from '../../store/configureStore';
import { ServiceAccountPageUnconnected, Props } from './ServiceAccountPage';
jest.mock('app/core/core', () => ({
@ -19,7 +17,6 @@ jest.mock('app/core/core', () => ({
}));
const setup = (propOverrides: Partial<Props>) => {
const store = configureStore();
const createServiceAccountTokenMock = jest.fn();
const deleteServiceAccountMock = jest.fn();
const deleteServiceAccountTokenMock = jest.fn();
@ -54,9 +51,9 @@ const setup = (propOverrides: Partial<Props>) => {
Object.assign(props, propOverrides);
const { rerender } = render(
<Provider store={store}>
<TestProvider>
<ServiceAccountPageUnconnected {...props} />
</Provider>
</TestProvider>
);
return {
rerender,

@ -1,12 +1,10 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { OrgRole, ServiceAccountDTO, ServiceAccountStateFilter } from 'app/types';
import { configureStore } from '../../store/configureStore';
import { Props, ServiceAccountsListPageUnconnected } from './ServiceAccountsListPage';
jest.mock('app/core/core', () => ({
@ -18,7 +16,6 @@ jest.mock('app/core/core', () => ({
}));
const setup = (propOverrides: Partial<Props>) => {
const store = configureStore();
const changeQueryMock = jest.fn();
const fetchACOptionsMock = jest.fn();
const fetchServiceAccountsMock = jest.fn();
@ -56,12 +53,12 @@ const setup = (propOverrides: Partial<Props>) => {
Object.assign(props, propOverrides);
const { rerender } = render(
<Provider store={store}>
<TestProvider>
<ServiceAccountsListPageUnconnected {...props} />
</Provider>
</TestProvider>
);
return {
rerender: (element: JSX.Element) => rerender(<Provider store={store}>{element}</Provider>),
rerender: (element: JSX.Element) => rerender(<TestProvider>{element}</TestProvider>),
props,
changeQueryMock,
fetchACOptionsMock,

@ -1,12 +1,10 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { BackendSrv, setBackendSrv } from '@grafana/runtime';
import { configureStore } from '../../store/configureStore';
import { CreateTeam } from './CreateTeam';
beforeEach(() => {
@ -35,11 +33,10 @@ setBackendSrv({
} as unknown as BackendSrv);
const setup = () => {
const store = configureStore();
return render(
<Provider store={store}>
<TestProvider>
<CreateTeam />
</Provider>
</TestProvider>
);
};

@ -1,11 +1,10 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { contextSrv, User } from 'app/core/services/context_srv';
import { configureStore } from '../../store/configureStore';
import { OrgRole, Team } from '../../types';
import { Props, TeamList } from './TeamList';
@ -17,7 +16,6 @@ jest.mock('app/core/config', () => ({
}));
const setup = (propOverrides?: object) => {
const store = configureStore();
const props: Props = {
teams: [] as Team[],
noTeams: false,
@ -41,9 +39,9 @@ const setup = (propOverrides?: object) => {
contextSrv.user = props.signedInUser;
render(
<Provider store={store}>
<TestProvider>
<TeamList {...props} />
</Provider>
</TestProvider>
);
};

@ -1,11 +1,10 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { TestProvider } from 'test/helpers/TestProvider';
import { createTheme } from '@grafana/data';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
import { User } from 'app/core/services/context_srv';
import { configureStore } from 'app/store/configureStore';
import { OrgRole, Team, TeamMember } from '../../types';
@ -64,7 +63,6 @@ jest.mock('./TeamGroupSync', () => {
});
const setup = (propOverrides?: object) => {
const store = configureStore();
const props: Props = {
...getRouteComponentProps({
match: {
@ -93,9 +91,9 @@ const setup = (propOverrides?: object) => {
Object.assign(props, propOverrides);
render(
<Provider store={store}>
<TestProvider>
<TeamPages {...props} />
</Provider>
</TestProvider>
);
};

@ -401,7 +401,7 @@ export function getAppRoutes(): RouteDescriptor[] {
{
path: '/login',
component: LoginPage,
pageClass: 'login-page sidemenu-hidden',
pageClass: 'login-page',
chromeless: true,
},
{
@ -409,7 +409,6 @@ export function getAppRoutes(): RouteDescriptor[] {
component: SafeDynamicImport(
() => import(/* webpackChunkName: "SignupInvited" */ 'app/features/invites/SignupInvited')
),
pageClass: 'sidemenu-hidden',
chromeless: true,
},
{
@ -419,7 +418,7 @@ export function getAppRoutes(): RouteDescriptor[] {
: SafeDynamicImport(
() => import(/* webpackChunkName "VerifyEmailPage"*/ 'app/core/components/Signup/VerifyEmailPage')
),
pageClass: 'login-page sidemenu-hidden',
pageClass: 'login-page',
chromeless: true,
},
{
@ -427,12 +426,11 @@ export function getAppRoutes(): RouteDescriptor[] {
component: config.disableUserSignUp
? () => <Redirect to="/login" />
: SafeDynamicImport(() => import(/* webpackChunkName "SignupPage"*/ 'app/core/components/Signup/SignupPage')),
pageClass: 'sidemenu-hidden login-page',
pageClass: 'login-page',
chromeless: true,
},
{
path: '/user/password/send-reset-email',
pageClass: 'sidemenu-hidden',
chromeless: true,
component: SafeDynamicImport(
() =>
@ -447,7 +445,7 @@ export function getAppRoutes(): RouteDescriptor[] {
/* webpackChunkName: "ChangePasswordPage" */ 'app/core/components/ForgottenPassword/ChangePasswordPage'
)
),
pageClass: 'sidemenu-hidden login-page',
pageClass: 'login-page',
chromeless: true,
},
{

@ -87,7 +87,6 @@ export interface PanelChangeViewPayload {}
export const dsRequestResponse = eventFactory<DataSourceResponsePayload>('ds-request-response');
export const dsRequestError = eventFactory<any>('ds-request-error');
export const toggleSidemenuHidden = eventFactory('toggle-sidemenu-hidden');
export const templateVariableValueUpdated = eventFactory('template-variable-value-updated');
export const graphClicked = eventFactory<GraphClickedPayload>('graph-click');

@ -1,7 +1,32 @@
import { ToolkitStore } from '@reduxjs/toolkit/dist/configureStore';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
const TestProvider = ({ children }: React.PropsWithChildren<{}>) => {
return <>{children}</>;
};
import { locationService } from '@grafana/runtime';
import { GrafanaContext, GrafanaContextType } from 'app/core/context/GrafanaContext';
import { configureStore } from 'app/store/configureStore';
import { StoreState } from 'app/types/store';
export default TestProvider;
export interface Props {
storeState?: Partial<StoreState>;
store?: ToolkitStore;
children: React.ReactNode;
grafanaContext?: GrafanaContextType;
}
/**
* Wrapps component in redux store provider, Router and GrafanaContext
*/
export function TestProvider(props: Props) {
const { store = configureStore(props.storeState), grafanaContext = getGrafanaContextMock(), children } = props;
return (
<Provider store={store}>
<Router history={locationService.getHistory()}>
<GrafanaContext.Provider value={grafanaContext}>{children}</GrafanaContext.Provider>
</Router>
</Provider>
);
}

@ -1,13 +1,13 @@
import { render } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Router, Route } from 'react-router-dom';
import { Route } from 'react-router-dom';
import { byRole, byTestId } from 'testing-library-selector';
import { selectors } from '@grafana/e2e-selectors';
import { locationService } from '@grafana/runtime';
import RuleEditor from 'app/features/alerting/unified/RuleEditor';
import { configureStore } from 'app/store/configureStore';
import { TestProvider } from './TestProvider';
export const ui = {
inputs: {
@ -36,15 +36,11 @@ export const ui = {
};
export function renderRuleEditor(identifier?: string) {
const store = configureStore();
locationService.push(identifier ? `/alerting/${identifier}/edit` : `/alerting/new`);
return render(
<Provider store={store}>
<Router history={locationService.getHistory()}>
<Route path={['/alerting/new', '/alerting/:id/edit']} component={RuleEditor} />
</Router>
</Provider>
<TestProvider>
<Route path={['/alerting/new', '/alerting/:id/edit']} component={RuleEditor} />
</TestProvider>
);
}

Loading…
Cancel
Save