diff --git a/pkg/services/navtree/navtreeimpl/navtree.go b/pkg/services/navtree/navtreeimpl/navtree.go
index 73d601b6ba3..16f0a5e231d 100644
--- a/pkg/services/navtree/navtreeimpl/navtree.go
+++ b/pkg/services/navtree/navtreeimpl/navtree.go
@@ -73,9 +73,7 @@ func (s *ServiceImpl) GetNavTree(c *models.ReqContext, hasEditPerm bool, prefs *
hasAccess := ac.HasAccess(s.accessControl, c)
treeRoot := &navtree.NavTreeRoot{}
- if s.features.IsEnabled(featuremgmt.FlagTopnav) {
- treeRoot.AddSection(s.getHomeNode(c, prefs))
- }
+ treeRoot.AddSection(s.getHomeNode(c, prefs))
if hasAccess(ac.ReqSignedIn, ac.EvalPermission(dashboards.ActionDashboardsRead)) {
starredItemsLinks, err := s.buildStarredItemsNavLinks(c)
@@ -224,7 +222,7 @@ func (s *ServiceImpl) getHomeNode(c *models.ReqContext, prefs *pref.Preference)
}
}
- return &navtree.NavLink{
+ homeNode := &navtree.NavLink{
Text: "Home",
Id: "home",
Url: homeUrl,
@@ -232,6 +230,10 @@ func (s *ServiceImpl) getHomeNode(c *models.ReqContext, prefs *pref.Preference)
Section: navtree.NavSectionCore,
SortWeight: navtree.WeightHome,
}
+ if !s.features.IsEnabled(featuremgmt.FlagTopnav) {
+ homeNode.HideFromMenu = true
+ }
+ return homeNode
}
func (s *ServiceImpl) addHelpLinks(treeRoot *navtree.NavTreeRoot, c *models.ReqContext) {
diff --git a/public/app/core/components/AppChrome/NavToolbar.tsx b/public/app/core/components/AppChrome/NavToolbar.tsx
index 12c4c46d481..59cc55b552e 100644
--- a/public/app/core/components/AppChrome/NavToolbar.tsx
+++ b/public/app/core/components/AppChrome/NavToolbar.tsx
@@ -33,7 +33,7 @@ export function NavToolbar({
}: Props) {
const homeNav = useSelector((state) => state.navIndex)[HOME_NAV_ID];
const styles = useStyles2(getStyles);
- const breadcrumbs = buildBreadcrumbs(homeNav, sectionNav, pageNav);
+ const breadcrumbs = buildBreadcrumbs(sectionNav, pageNav, homeNav);
return (
diff --git a/public/app/core/components/Breadcrumbs/utils.test.ts b/public/app/core/components/Breadcrumbs/utils.test.ts
index c84ca5d0c6d..c696d65a4d3 100644
--- a/public/app/core/components/Breadcrumbs/utils.test.ts
+++ b/public/app/core/components/Breadcrumbs/utils.test.ts
@@ -15,7 +15,7 @@ describe('breadcrumb utils', () => {
text: 'My section',
url: '/my-section',
};
- expect(buildBreadcrumbs(mockHomeNav, sectionNav)).toEqual([{ text: 'My section', href: '/my-section' }]);
+ expect(buildBreadcrumbs(sectionNav)).toEqual([{ text: 'My section', href: '/my-section' }]);
});
it('includes breadcrumbs for the page nav', () => {
@@ -28,7 +28,7 @@ describe('breadcrumb utils', () => {
text: 'My page',
url: '/my-page',
};
- expect(buildBreadcrumbs(mockHomeNav, sectionNav, pageNav)).toEqual([
+ expect(buildBreadcrumbs(sectionNav, pageNav)).toEqual([
{ text: 'My section', href: '/my-section' },
{ text: 'My page', href: '/my-page' },
]);
@@ -43,7 +43,7 @@ describe('breadcrumb utils', () => {
url: '/my-parent-section',
},
};
- expect(buildBreadcrumbs(mockHomeNav, sectionNav)).toEqual([
+ expect(buildBreadcrumbs(sectionNav)).toEqual([
{ text: 'My parent section', href: '/my-parent-section' },
{ text: 'My section', href: '/my-section' },
]);
@@ -66,7 +66,7 @@ describe('breadcrumb utils', () => {
url: '/my-parent-section',
},
};
- expect(buildBreadcrumbs(mockHomeNav, sectionNav, pageNav)).toEqual([
+ expect(buildBreadcrumbs(sectionNav, pageNav)).toEqual([
{ text: 'My parent section', href: '/my-parent-section' },
{ text: 'My section', href: '/my-section' },
{ text: 'My parent page', href: '/my-parent-page' },
@@ -91,7 +91,7 @@ describe('breadcrumb utils', () => {
url: '/my-parent-section',
},
};
- expect(buildBreadcrumbs(mockHomeNav, sectionNav, pageNav)).toEqual([
+ expect(buildBreadcrumbs(sectionNav, pageNav, mockHomeNav)).toEqual([
{ text: 'Home', href: '/home' },
{ text: 'My page', href: '/my-page' },
]);
@@ -114,7 +114,7 @@ describe('breadcrumb utils', () => {
url: '/my-parent-section',
},
};
- expect(buildBreadcrumbs(mockHomeNav, sectionNav, pageNav)).toEqual([
+ expect(buildBreadcrumbs(sectionNav, pageNav, mockHomeNav)).toEqual([
{ text: 'Home', href: '/home?orgId=1' },
{ text: 'My page', href: '/my-page' },
]);
@@ -137,7 +137,7 @@ describe('breadcrumb utils', () => {
url: '/my-parent-section',
},
};
- expect(buildBreadcrumbs(mockHomeNav, sectionNav, pageNav)).toEqual([
+ expect(buildBreadcrumbs(sectionNav, pageNav, mockHomeNav)).toEqual([
{ text: 'My parent section', href: '/my-parent-section' },
{ text: 'My section', href: '/my-section' },
{ text: 'My parent page', href: '/home?orgId=1&editview=settings' },
diff --git a/public/app/core/components/Breadcrumbs/utils.ts b/public/app/core/components/Breadcrumbs/utils.ts
index c41022f7f26..cbf68fefb50 100644
--- a/public/app/core/components/Breadcrumbs/utils.ts
+++ b/public/app/core/components/Breadcrumbs/utils.ts
@@ -4,7 +4,7 @@ import { getNavTitle } from '../NavBar/navBarItem-translations';
import { Breadcrumb } from './types';
-export function buildBreadcrumbs(homeNav: NavModelItem, sectionNav: NavModelItem, pageNav?: NavModelItem) {
+export function buildBreadcrumbs(sectionNav: NavModelItem, pageNav?: NavModelItem, homeNav?: NavModelItem) {
const crumbs: Breadcrumb[] = [];
let foundHome = false;
@@ -17,7 +17,7 @@ export function buildBreadcrumbs(homeNav: NavModelItem, sectionNav: NavModelItem
urlToMatch += `?editview=${urlSearchParams.get('editview')}`;
}
if (!foundHome && !node.hideFromBreadcrumbs) {
- if (urlToMatch === homeNav.url) {
+ if (homeNav && urlToMatch === homeNav.url) {
crumbs.unshift({ text: getNavTitle(homeNav.id) ?? homeNav.text, href: node.url ?? '' });
foundHome = true;
} else {
diff --git a/public/app/core/components/NavBar/NavBar.tsx b/public/app/core/components/NavBar/NavBar.tsx
index e1765c71d61..9fc506b3ef0 100644
--- a/public/app/core/components/NavBar/NavBar.tsx
+++ b/public/app/core/components/NavBar/NavBar.tsx
@@ -61,7 +61,7 @@ export const NavBar = React.memo(() => {
menuOpen
);
- const navTree = cloneDeep(navBarTree);
+ const navTree = cloneDeep(navBarTree).filter((item) => item.hideFromMenu !== true);
const coreItems = navTree
.filter((item) => item.section === NavSection.Core)
diff --git a/public/app/core/components/Page/usePageTitle.ts b/public/app/core/components/Page/usePageTitle.ts
index 730c696fc27..7a9e0e025a5 100644
--- a/public/app/core/components/Page/usePageTitle.ts
+++ b/public/app/core/components/Page/usePageTitle.ts
@@ -1,37 +1,23 @@
import { useEffect } from 'react';
import { NavModel, NavModelItem } from '@grafana/data';
+import { HOME_NAV_ID } from 'app/core/reducers/navModel';
+import { useSelector } from 'app/types';
import { Branding } from '../Branding/Branding';
+import { buildBreadcrumbs } from '../Breadcrumbs/utils';
export function usePageTitle(navModel?: NavModel, pageNav?: NavModelItem) {
+ const homeNav = useSelector((state) => state.navIndex)[HOME_NAV_ID];
useEffect(() => {
- const parts: string[] = [];
- if (pageNav) {
- if (pageNav.children) {
- const activePage = pageNav.children.find((x) => x.active);
- if (activePage) {
- addTitleSegment(parts, activePage);
- }
- }
- addTitleSegment(parts, pageNav);
- }
+ const sectionNav = (navModel?.node !== navModel?.main ? navModel?.node : navModel?.main) ?? { text: 'Grafana' };
+ const parts: string[] = buildBreadcrumbs(sectionNav, pageNav, homeNav)
+ .map((crumb) => crumb.text)
+ .reverse();
- if (navModel) {
- if (navModel.node !== navModel.main) {
- addTitleSegment(parts, navModel.node);
- }
- addTitleSegment(parts, navModel.main);
- }
-
- parts.push(Branding.AppTitle);
+ // Override `Home` with the custom brand title
+ parts[parts.length - 1] = Branding.AppTitle;
document.title = parts.join(' - ');
- }, [navModel, pageNav]);
-}
-
-function addTitleSegment(parts: string[], node: NavModelItem) {
- if (!node.hideFromBreadcrumbs) {
- parts.push(node.text);
- }
+ }, [homeNav, navModel, pageNav]);
}
diff --git a/public/app/core/components/PageNew/Page.test.tsx b/public/app/core/components/PageNew/Page.test.tsx
index 4ea9862923b..66556318fa1 100644
--- a/public/app/core/components/PageNew/Page.test.tsx
+++ b/public/app/core/components/PageNew/Page.test.tsx
@@ -6,6 +6,7 @@ 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';
@@ -19,9 +20,12 @@ const pageNav: NavModelItem = {
{ text: 'pageNav child2', url: '2' },
],
};
-
const setup = (props: Partial
) => {
config.bootData.navTree = [
+ {
+ id: HOME_NAV_ID,
+ text: 'Home',
+ },
{
text: 'Section name',
id: 'section',
@@ -92,7 +96,7 @@ describe('Render', () => {
it('should update document title', async () => {
setup({ navId: 'child1', pageNav });
- expect(document.title).toBe('pageNav child1 - pageNav title - Child1 - Section name - Grafana');
+ expect(document.title).toBe('pageNav title - Child1 - Section name - Grafana');
});
it('should not include hideFromBreadcrumb nodes in title', async () => {
diff --git a/public/app/core/navigation/GrafanaRoute.test.tsx b/public/app/core/navigation/GrafanaRoute.test.tsx
index bf6efb99c83..396fe7e802a 100644
--- a/public/app/core/navigation/GrafanaRoute.test.tsx
+++ b/public/app/core/navigation/GrafanaRoute.test.tsx
@@ -1,16 +1,19 @@
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 { 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) {
+ const store = configureStore();
const props: Props = {
location: { search: '?query=hello&test=asd' } as any,
history: {} as any,
@@ -25,7 +28,9 @@ function setup(overrides: Partial) {
render(
-
+
+
+
);
diff --git a/public/app/core/services/context_srv.ts b/public/app/core/services/context_srv.ts
index c8511c5aaa9..7a7f5f53f74 100644
--- a/public/app/core/services/context_srv.ts
+++ b/public/app/core/services/context_srv.ts
@@ -69,7 +69,7 @@ export class ContextSrv {
constructor() {
if (!config.bootData) {
- config.bootData = { user: {}, settings: {} } as any;
+ config.bootData = { user: {}, settings: {}, navTree: [] } as any;
}
this.user = new User();
diff --git a/public/app/features/alerting/AlertRuleList.test.tsx b/public/app/features/alerting/AlertRuleList.test.tsx
index c146cdb322d..2589b5f4cd6 100644
--- a/public/app/features/alerting/AlertRuleList.test.tsx
+++ b/public/app/features/alerting/AlertRuleList.test.tsx
@@ -1,6 +1,7 @@
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';
@@ -8,6 +9,7 @@ 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';
@@ -29,15 +31,20 @@ const defaultProps: Props = {
};
const setup = (propOverrides?: object) => {
+ const store = configureStore();
const props: Props = {
...defaultProps,
...propOverrides,
};
- const { rerender } = render();
+ const { rerender } = render(
+
+
+
+ );
return {
- rerender,
+ rerender: (element: JSX.Element) => rerender({element}),
};
};
diff --git a/public/app/features/api-keys/ApiKeysPage.test.tsx b/public/app/features/api-keys/ApiKeysPage.test.tsx
index fd61e6683be..f1bcc796342 100644
--- a/public/app/features/api-keys/ApiKeysPage.test.tsx
+++ b/public/app/features/api-keys/ApiKeysPage.test.tsx
@@ -1,12 +1,14 @@
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 { 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';
@@ -22,6 +24,7 @@ jest.mock('app/core/core', () => {
});
const setup = (propOverrides: Partial) => {
+ const store = configureStore();
const loadApiKeysMock = jest.fn();
const deleteApiKeyMock = jest.fn();
const migrateApiKeyMock = jest.fn();
@@ -54,9 +57,13 @@ const setup = (propOverrides: Partial) => {
Object.assign(props, propOverrides);
- const { rerender } = render();
+ const { rerender } = render(
+
+
+
+ );
return {
- rerender,
+ rerender: (element: JSX.Element) => rerender({element}),
props,
loadApiKeysMock,
setSearchQueryMock,
diff --git a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
index a510c4b0eb8..3d68416cfa7 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
@@ -2,6 +2,7 @@ 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';
@@ -10,11 +11,13 @@ import { locationService, setAngularLoader, setDataSourceSrv } from '@grafana/ru
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 { AnnotationsSettings } from './AnnotationsSettings';
function setup(dashboard: DashboardModel, editIndex?: number) {
+ const store = configureStore();
const sectionNav = {
main: { text: 'Dashboard' },
node: {
@@ -24,9 +27,11 @@ function setup(dashboard: DashboardModel, editIndex?: number) {
return render(
-
-
-
+
+
+
+
+
);
}
diff --git a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
index e8c4aba49d1..227765f674d 100644
--- a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
@@ -1,6 +1,7 @@
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 { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
@@ -10,6 +11,7 @@ import { selectors } from '@grafana/e2e-selectors';
import { BackendSrv, setBackendSrv } from '@grafana/runtime';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
+import { configureStore } from '../../../../store/configureStore';
import { DashboardModel } from '../../state';
import { GeneralSettingsUnconnected as GeneralSettings, Props } from './GeneralSettings';
@@ -19,6 +21,7 @@ setBackendSrv({
} as unknown as BackendSrv);
const setupTestContext = (options: Partial) => {
+ const store = configureStore();
const defaults: Props = {
dashboard: new DashboardModel(
{
@@ -49,9 +52,11 @@ const setupTestContext = (options: Partial) => {
const { rerender } = render(
-
-
-
+
+
+
+
+
);
diff --git a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
index f3c1a51b72c..c6716812b13 100644
--- a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
@@ -2,6 +2,7 @@ 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 { Router } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
@@ -9,11 +10,13 @@ import { selectors } from '@grafana/e2e-selectors';
import { locationService } from '@grafana/runtime';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
+import { configureStore } from '../../../../store/configureStore';
import { DashboardModel } from '../../state';
import { DashboardSettings } from './DashboardSettings';
function setup(dashboard: DashboardModel) {
+ const store = configureStore();
const sectionNav = {
main: { text: 'Dashboard' },
node: {
@@ -24,9 +27,11 @@ function setup(dashboard: DashboardModel) {
// Need to use DashboardSettings here as it's responsible for fetching the state back from location
return render(
-
-
-
+
+
+
+
+
);
}
diff --git a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
index 2ab45f6268d..9de7e2b0ff1 100644
--- a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
@@ -2,11 +2,13 @@ import { within } from '@testing-library/dom';
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 { BrowserRouter } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
+import { configureStore } from '../../../../store/configureStore';
import { DashboardModel } from '../../state/DashboardModel';
import { historySrv } from '../VersionHistory/HistorySrv';
@@ -27,6 +29,7 @@ const queryByFullText = (text: string) =>
});
function setup() {
+ const store = configureStore();
const dashboard = new DashboardModel({
id: 74,
version: 11,
@@ -43,9 +46,11 @@ function setup() {
return render(
-
-
-
+
+
+
+
+
);
}
diff --git a/public/app/features/dashboard/containers/DashboardPage.test.tsx b/public/app/features/dashboard/containers/DashboardPage.test.tsx
index be37870e6a3..5dd77df63b7 100644
--- a/public/app/features/dashboard/containers/DashboardPage.test.tsx
+++ b/public/app/features/dashboard/containers/DashboardPage.test.tsx
@@ -13,6 +13,7 @@ import { config, locationService, setDataSourceSrv } from '@grafana/runtime';
import { notifyApp } from 'app/core/actions';
import { GrafanaContext } from 'app/core/context/GrafanaContext';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
+import { HOME_NAV_ID } from 'app/core/reducers/navModel';
import { DashboardInitPhase, DashboardMeta, DashboardRoutes } from 'app/types';
import { configureStore } from '../../../store/configureStore';
@@ -105,7 +106,10 @@ function dashboardPageScenario(description: string, scenarioFn: (ctx: ScenarioCo
setupFn = fn;
},
mount: (propOverrides?: Partial) => {
- config.bootData.navTree = [{ text: 'Dashboards', id: 'dashboards' }];
+ config.bootData.navTree = [
+ { text: 'Dashboards', id: 'dashboards' },
+ { text: 'Home', id: HOME_NAV_ID },
+ ];
const store = configureStore();
const props: Props = {
@@ -114,7 +118,8 @@ function dashboardPageScenario(description: string, scenarioFn: (ctx: ScenarioCo
route: { routeName: DashboardRoutes.Normal } as any,
}),
navIndex: {
- dashboards: { text: 'Dashboards' },
+ dashboards: { text: 'Dashboards', id: 'dashboards', parentItem: { text: 'Home', id: HOME_NAV_ID } },
+ [HOME_NAV_ID]: { text: 'Home', id: HOME_NAV_ID },
},
initPhase: DashboardInitPhase.NotStarted,
initError: null,
diff --git a/public/app/features/invites/SignupInvited.test.tsx b/public/app/features/invites/SignupInvited.test.tsx
index d16170371e9..693ff41b0e2 100644
--- a/public/app/features/invites/SignupInvited.test.tsx
+++ b/public/app/features/invites/SignupInvited.test.tsx
@@ -1,10 +1,12 @@
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 { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
import { backendSrv } from '../../core/services/backend_srv';
+import { configureStore } from '../../store/configureStore';
import { SignupInvitedPage, Props } from './SignupInvited';
@@ -28,6 +30,7 @@ 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);
@@ -43,7 +46,11 @@ async function setupTestContext({ get = defaultGet }: { get?: typeof defaultGet
}),
};
- render();
+ render(
+
+
+
+ );
await waitFor(() => expect(getSpy).toHaveBeenCalled());
expect(getSpy).toHaveBeenCalledTimes(1);
diff --git a/public/app/features/org/OrgDetailsPage.test.tsx b/public/app/features/org/OrgDetailsPage.test.tsx
index 018e589d471..50c086d81e9 100644
--- a/public/app/features/org/OrgDetailsPage.test.tsx
+++ b/public/app/features/org/OrgDetailsPage.test.tsx
@@ -6,9 +6,9 @@ import { mockToolkitActionCreator } from 'test/core/redux/mocks';
import { NavModel } from '@grafana/data';
import { ModalManager } from 'app/core/services/ModalManager';
-import { configureStore } from 'app/store/configureStore';
import { backendSrv } from '../../core/services/backend_srv';
+import { configureStore } from '../../store/configureStore';
import { Organization } from '../../types';
import { OrgDetailsPage, Props } from './OrgDetailsPage';
@@ -37,6 +37,7 @@ 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');
@@ -62,7 +63,7 @@ const setup = (propOverrides?: object) => {
Object.assign(props, propOverrides);
render(
-
+
);
diff --git a/public/app/features/playlist/PlaylistEditPage.test.tsx b/public/app/features/playlist/PlaylistEditPage.test.tsx
index d1894a85839..a64bab76278 100644
--- a/public/app/features/playlist/PlaylistEditPage.test.tsx
+++ b/public/app/features/playlist/PlaylistEditPage.test.tsx
@@ -1,10 +1,13 @@
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 { 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';
@@ -21,6 +24,7 @@ jest.mock('app/core/components/TagFilter/TagFilter', () => ({
async function getTestContext({ name, interval, items, uid }: Partial = {}) {
jest.clearAllMocks();
+ const store = configureStore();
const playlist = { name, items, interval, uid } as unknown as Playlist;
const queryParams = {};
const route: any = {};
@@ -36,7 +40,9 @@ async function getTestContext({ name, interval, items, uid }: Partial
uid: 'foo',
});
const { rerender } = render(
-
+
+
+
);
await waitFor(() => expect(getMock).toHaveBeenCalledTimes(1));
diff --git a/public/app/features/playlist/PlaylistNewPage.test.tsx b/public/app/features/playlist/PlaylistNewPage.test.tsx
index 704dd9841fb..69cabd81048 100644
--- a/public/app/features/playlist/PlaylistNewPage.test.tsx
+++ b/public/app/features/playlist/PlaylistNewPage.test.tsx
@@ -1,10 +1,13 @@
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 { selectors } from '@grafana/e2e-selectors';
import { locationService } from '@grafana/runtime';
-import { backendSrv } from 'app/core/services/backend_srv';
+
+import { backendSrv } from '../../core/services/backend_srv';
+import { configureStore } from '../../store/configureStore';
import { PlaylistNewPage } from './PlaylistNewPage';
import { Playlist } from './types';
@@ -21,11 +24,16 @@ jest.mock('app/core/components/TagFilter/TagFilter', () => ({
}));
function getTestContext({ name, interval, items }: Partial = {}) {
+ const store = configureStore();
jest.clearAllMocks();
const playlist = { name, items, interval } as unknown as Playlist;
const backendSrvMock = jest.spyOn(backendSrv, 'post');
- const { rerender } = render();
+ const { rerender } = render(
+
+
+
+ );
return { playlist, rerender, backendSrvMock };
}
diff --git a/public/app/features/playlist/PlaylistPage.test.tsx b/public/app/features/playlist/PlaylistPage.test.tsx
index 39b32744c00..70f1b6924b0 100644
--- a/public/app/features/playlist/PlaylistPage.test.tsx
+++ b/public/app/features/playlist/PlaylistPage.test.tsx
@@ -1,8 +1,11 @@
import { render, waitFor } from '@testing-library/react';
import React from 'react';
+import { Provider } from 'react-redux';
import { contextSrv } from 'app/core/services/context_srv';
+import { configureStore } from '../../store/configureStore';
+
import { PlaylistPage } from './PlaylistPage';
const fnMock = jest.fn();
@@ -21,7 +24,12 @@ jest.mock('app/core/services/context_srv', () => ({
}));
function getTestContext() {
- return render();
+ const store = configureStore();
+ return render(
+
+
+
+ );
}
describe('PlaylistPage', () => {
diff --git a/public/app/features/profile/ChangePasswordPage.test.tsx b/public/app/features/profile/ChangePasswordPage.test.tsx
index 41cca32c284..dcef679b234 100644
--- a/public/app/features/profile/ChangePasswordPage.test.tsx
+++ b/public/app/features/profile/ChangePasswordPage.test.tsx
@@ -1,10 +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 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';
@@ -26,6 +28,7 @@ const defaultProps: Props = {
};
async function getTestContext(overrides: Partial = {}) {
+ const store = configureStore();
jest.clearAllMocks();
jest.spyOn(backendSrv, 'get').mockResolvedValue({
id: 1,
@@ -38,7 +41,11 @@ async function getTestContext(overrides: Partial = {}) {
});
const props = { ...defaultProps, ...overrides };
- const { rerender } = render();
+ const { rerender } = render(
+
+
+
+ );
await waitFor(() => expect(props.loadUser).toHaveBeenCalledTimes(1));
diff --git a/public/app/features/profile/UserProfileEditPage.test.tsx b/public/app/features/profile/UserProfileEditPage.test.tsx
index 19761e364a3..31ecb2d0fad 100644
--- a/public/app/features/profile/UserProfileEditPage.test.tsx
+++ b/public/app/features/profile/UserProfileEditPage.test.tsx
@@ -2,12 +2,14 @@ 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 { backendSrv } from '../../core/services/backend_srv';
+import { configureStore } from '../../store/configureStore';
import { TeamPermissionLevel } from '../../types';
import { Props, UserProfileEditPage } from './UserProfileEditPage';
@@ -96,6 +98,7 @@ function getSelectors() {
}
async function getTestContext(overrides: Partial = {}) {
+ const store = configureStore();
jest.clearAllMocks();
const putSpy = jest.spyOn(backendSrv, 'put');
const getSpy = jest
@@ -105,9 +108,11 @@ async function getTestContext(overrides: Partial = {}) {
const props = { ...defaultProps, ...overrides };
const { rerender } = render(
-
-
-
+
+
+
+
+
);
await waitFor(() => expect(props.initUserProfilePage).toHaveBeenCalledTimes(1));
diff --git a/public/app/features/scenes/components/NestedScene.test.tsx b/public/app/features/scenes/components/NestedScene.test.tsx
index 0b9d0b16355..06d61eeacc3 100644
--- a/public/app/features/scenes/components/NestedScene.test.tsx
+++ b/public/app/features/scenes/components/NestedScene.test.tsx
@@ -1,5 +1,8 @@
import { screen, render } from '@testing-library/react';
import React from 'react';
+import { Provider } from 'react-redux';
+
+import { configureStore } from '../../../store/configureStore';
import { NestedScene } from './NestedScene';
import { Scene } from './Scene';
@@ -7,6 +10,7 @@ import { SceneCanvasText } from './SceneCanvasText';
import { SceneFlexLayout } from './layout/SceneFlexLayout';
function setup() {
+ const store = configureStore();
const scene = new Scene({
title: 'Hello',
layout: new SceneFlexLayout({
@@ -23,7 +27,11 @@ function setup() {
}),
});
- render();
+ render(
+
+
+
+ );
}
describe('NestedScene', () => {
diff --git a/public/app/features/scenes/components/layout/SceneGridLayout.test.tsx b/public/app/features/scenes/components/layout/SceneGridLayout.test.tsx
index 07c1e585d25..677f1a8a6d0 100644
--- a/public/app/features/scenes/components/layout/SceneGridLayout.test.tsx
+++ b/public/app/features/scenes/components/layout/SceneGridLayout.test.tsx
@@ -1,6 +1,8 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
+import { Provider } from 'react-redux';
+import { configureStore } from '../../../../store/configureStore';
import { SceneObjectBase } from '../../core/SceneObjectBase';
import { SceneComponentProps, SceneLayoutChildState } from '../../core/types';
import { Scene } from '../Scene';
@@ -21,6 +23,11 @@ class TestObject extends SceneObjectBase {
};
}
+function renderWithProvider(element: JSX.Element) {
+ const store = configureStore();
+ return render({element});
+}
+
describe('SceneGridLayout', () => {
describe('rendering', () => {
it('should render all grid children', async () => {
@@ -34,7 +41,7 @@ describe('SceneGridLayout', () => {
}),
});
- render();
+ renderWithProvider();
expect(screen.queryAllByTestId('test-object')).toHaveLength(2);
});
@@ -57,7 +64,7 @@ describe('SceneGridLayout', () => {
}),
});
- render();
+ renderWithProvider();
expect(screen.queryAllByTestId('test-object')).toHaveLength(2);
});
@@ -80,7 +87,7 @@ describe('SceneGridLayout', () => {
}),
});
- render();
+ renderWithProvider();
expect(screen.queryAllByTestId('test-object')).toHaveLength(3);
});
diff --git a/public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx b/public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx
index 0eca4499524..e9dfe18c306 100644
--- a/public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx
@@ -1,6 +1,9 @@
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 { ServiceAccountCreatePage, Props } from './ServiceAccountCreatePage';
@@ -9,6 +12,7 @@ const patchMock = jest.fn().mockResolvedValue({});
const putMock = jest.fn().mockResolvedValue({});
jest.mock('@grafana/runtime', () => ({
+ ...jest.requireActual('@grafana/runtime'),
getBackendSrv: () => ({
post: postMock,
patch: patchMock,
@@ -41,6 +45,7 @@ jest.mock('app/core/core', () => ({
}));
const setup = (propOverrides: Partial) => {
+ const store = configureStore();
const props: Props = {
navModel: {
main: {
@@ -54,7 +59,11 @@ const setup = (propOverrides: Partial) => {
Object.assign(props, propOverrides);
- render();
+ render(
+
+
+
+ );
};
describe('ServiceAccountCreatePage tests', () => {
diff --git a/public/app/features/serviceaccounts/ServiceAccountPage.test.tsx b/public/app/features/serviceaccounts/ServiceAccountPage.test.tsx
index c70c984d064..9a3e5800c70 100644
--- a/public/app/features/serviceaccounts/ServiceAccountPage.test.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountPage.test.tsx
@@ -1,9 +1,12 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
+import { Provider } from 'react-redux';
import { ApiKey, OrgRole, ServiceAccountDTO } from 'app/types';
+import { configureStore } from '../../store/configureStore';
+
import { ServiceAccountPageUnconnected, Props } from './ServiceAccountPage';
jest.mock('app/core/core', () => ({
@@ -16,6 +19,7 @@ jest.mock('app/core/core', () => ({
}));
const setup = (propOverrides: Partial) => {
+ const store = configureStore();
const createServiceAccountTokenMock = jest.fn();
const deleteServiceAccountMock = jest.fn();
const deleteServiceAccountTokenMock = jest.fn();
@@ -49,7 +53,11 @@ const setup = (propOverrides: Partial) => {
Object.assign(props, propOverrides);
- const { rerender } = render();
+ const { rerender } = render(
+
+
+
+ );
return {
rerender,
props,
diff --git a/public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx b/public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx
index 632c9126c8e..4e4d74ec145 100644
--- a/public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx
@@ -1,9 +1,12 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
+import { Provider } from 'react-redux';
import { OrgRole, ServiceAccountDTO, ServiceAccountStateFilter } from 'app/types';
+import { configureStore } from '../../store/configureStore';
+
import { Props, ServiceAccountsListPageUnconnected } from './ServiceAccountsListPage';
jest.mock('app/core/core', () => ({
@@ -15,6 +18,7 @@ jest.mock('app/core/core', () => ({
}));
const setup = (propOverrides: Partial) => {
+ const store = configureStore();
const changeQueryMock = jest.fn();
const fetchACOptionsMock = jest.fn();
const fetchServiceAccountsMock = jest.fn();
@@ -51,9 +55,13 @@ const setup = (propOverrides: Partial) => {
Object.assign(props, propOverrides);
- const { rerender } = render();
+ const { rerender } = render(
+
+
+
+ );
return {
- rerender,
+ rerender: (element: JSX.Element) => rerender({element}),
props,
changeQueryMock,
fetchACOptionsMock,
diff --git a/public/app/features/teams/CreateTeam.test.tsx b/public/app/features/teams/CreateTeam.test.tsx
index 7ab05634da9..3cfdbb310ee 100644
--- a/public/app/features/teams/CreateTeam.test.tsx
+++ b/public/app/features/teams/CreateTeam.test.tsx
@@ -1,9 +1,12 @@
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 { BackendSrv, setBackendSrv } from '@grafana/runtime';
+import { configureStore } from '../../store/configureStore';
+
import { CreateTeam } from './CreateTeam';
beforeEach(() => {
@@ -32,7 +35,12 @@ setBackendSrv({
} as unknown as BackendSrv);
const setup = () => {
- return render();
+ const store = configureStore();
+ return render(
+
+
+
+ );
};
describe('Create team', () => {
diff --git a/public/app/features/teams/TeamList.test.tsx b/public/app/features/teams/TeamList.test.tsx
index 09a144b5998..3bb2dd63bd4 100644
--- a/public/app/features/teams/TeamList.test.tsx
+++ b/public/app/features/teams/TeamList.test.tsx
@@ -1,10 +1,12 @@
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 { mockToolkitActionCreator } from 'test/core/redux/mocks';
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,6 +19,7 @@ jest.mock('app/core/config', () => ({
}));
const setup = (propOverrides?: object) => {
+ const store = configureStore();
const props: Props = {
teams: [] as Team[],
loadTeams: jest.fn(),
@@ -38,7 +41,11 @@ const setup = (propOverrides?: object) => {
contextSrv.user = props.signedInUser;
- render();
+ render(
+
+
+
+ );
};
describe('TeamList', () => {