mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
Navigation: share logic between buildBreadcrumbs
and usePageTitle
(#58819)
* simplify usePageTitle logic a bit * use buildBreadcrumbs logic in usePageTitle * always add home item to navTree, fix some tests * fix remaining unit tests
This commit is contained in:
parent
26a7423151
commit
824a562b03
@ -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))
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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 (
|
||||
<div className={styles.pageToolbar}>
|
||||
|
@ -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' },
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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<PageProps>) => {
|
||||
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 () => {
|
||||
|
@ -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<Props>) {
|
||||
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<Props>) {
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<GrafanaContext.Provider value={getGrafanaContextMock()}>
|
||||
<Provider store={store}>
|
||||
<GrafanaRoute {...props} />
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
@ -71,7 +71,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();
|
||||
|
@ -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(<AlertRuleListUnconnected {...props} />);
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<AlertRuleListUnconnected {...props} />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
return {
|
||||
rerender,
|
||||
rerender: (element: JSX.Element) => rerender(<Provider store={store}>{element}</Provider>),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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<Props>) => {
|
||||
const store = configureStore();
|
||||
const loadApiKeysMock = jest.fn();
|
||||
const deleteApiKeyMock = jest.fn();
|
||||
const migrateApiKeyMock = jest.fn();
|
||||
@ -54,9 +57,13 @@ const setup = (propOverrides: Partial<Props>) => {
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
const { rerender } = render(<ApiKeysPageUnconnected {...props} />);
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<ApiKeysPageUnconnected {...props} />
|
||||
</Provider>
|
||||
);
|
||||
return {
|
||||
rerender,
|
||||
rerender: (element: JSX.Element) => rerender(<Provider store={store}>{element}</Provider>),
|
||||
props,
|
||||
loadApiKeysMock,
|
||||
setSearchQueryMock,
|
||||
|
@ -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(
|
||||
<GrafanaContext.Provider value={getGrafanaContextMock()}>
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<AnnotationsSettings sectionNav={sectionNav} dashboard={dashboard} editIndex={editIndex} />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -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<Props>) => {
|
||||
const store = configureStore();
|
||||
const defaults: Props = {
|
||||
dashboard: new DashboardModel(
|
||||
{
|
||||
@ -49,9 +52,11 @@ const setupTestContext = (options: Partial<Props>) => {
|
||||
|
||||
const { rerender } = render(
|
||||
<GrafanaContext.Provider value={getGrafanaContextMock()}>
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<GeneralSettings {...props} />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
|
||||
|
@ -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(
|
||||
<GrafanaContext.Provider value={getGrafanaContextMock()}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<DashboardSettings editview="links" dashboard={dashboard} sectionNav={sectionNav} pageNav={sectionNav.node} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -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(
|
||||
<GrafanaContext.Provider value={getGrafanaContextMock()}>
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<VersionsSettings sectionNav={sectionNav} dashboard={dashboard} />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -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<Props>) => {
|
||||
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,
|
||||
|
@ -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(<SignupInvitedPage {...props} />);
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<SignupInvitedPage {...props} />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
await waitFor(() => expect(getSpy).toHaveBeenCalled());
|
||||
expect(getSpy).toHaveBeenCalledTimes(1);
|
||||
|
@ -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(
|
||||
<Provider store={configureStore()}>
|
||||
<Provider store={store}>
|
||||
<OrgDetailsPage {...props} />
|
||||
</Provider>
|
||||
);
|
||||
|
@ -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<Playlist> = {}) {
|
||||
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<Playlist>
|
||||
uid: 'foo',
|
||||
});
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<PlaylistEditPage queryParams={queryParams} route={route} match={match} location={location} history={history} />
|
||||
</Provider>
|
||||
);
|
||||
await waitFor(() => expect(getMock).toHaveBeenCalledTimes(1));
|
||||
|
||||
|
@ -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<Playlist> = {}) {
|
||||
const store = configureStore();
|
||||
jest.clearAllMocks();
|
||||
const playlist = { name, items, interval } as unknown as Playlist;
|
||||
const backendSrvMock = jest.spyOn(backendSrv, 'post');
|
||||
|
||||
const { rerender } = render(<PlaylistNewPage />);
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<PlaylistNewPage />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
return { playlist, rerender, backendSrvMock };
|
||||
}
|
||||
|
@ -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(<PlaylistPage />);
|
||||
const store = configureStore();
|
||||
return render(
|
||||
<Provider store={store}>
|
||||
<PlaylistPage />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
describe('PlaylistPage', () => {
|
||||
|
@ -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<Props> = {}) {
|
||||
const store = configureStore();
|
||||
jest.clearAllMocks();
|
||||
jest.spyOn(backendSrv, 'get').mockResolvedValue({
|
||||
id: 1,
|
||||
@ -38,7 +41,11 @@ async function getTestContext(overrides: Partial<Props> = {}) {
|
||||
});
|
||||
|
||||
const props = { ...defaultProps, ...overrides };
|
||||
const { rerender } = render(<ChangePasswordPage {...props} />);
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<ChangePasswordPage {...props} />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
await waitFor(() => expect(props.loadUser).toHaveBeenCalledTimes(1));
|
||||
|
||||
|
@ -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<Props> = {}) {
|
||||
const store = configureStore();
|
||||
jest.clearAllMocks();
|
||||
const putSpy = jest.spyOn(backendSrv, 'put');
|
||||
const getSpy = jest
|
||||
@ -105,9 +108,11 @@ async function getTestContext(overrides: Partial<Props> = {}) {
|
||||
|
||||
const props = { ...defaultProps, ...overrides };
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<TestProvider>
|
||||
<UserProfileEditPage {...props} />
|
||||
</TestProvider>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
await waitFor(() => expect(props.initUserProfilePage).toHaveBeenCalledTimes(1));
|
||||
|
@ -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(<scene.Component model={scene} />);
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<scene.Component model={scene} />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
describe('NestedScene', () => {
|
||||
|
@ -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<SceneLayoutChildState> {
|
||||
};
|
||||
}
|
||||
|
||||
function renderWithProvider(element: JSX.Element) {
|
||||
const store = configureStore();
|
||||
return render(<Provider store={store}>{element}</Provider>);
|
||||
}
|
||||
|
||||
describe('SceneGridLayout', () => {
|
||||
describe('rendering', () => {
|
||||
it('should render all grid children', async () => {
|
||||
@ -34,7 +41,7 @@ describe('SceneGridLayout', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
render(<scene.Component model={scene} />);
|
||||
renderWithProvider(<scene.Component model={scene} />);
|
||||
|
||||
expect(screen.queryAllByTestId('test-object')).toHaveLength(2);
|
||||
});
|
||||
@ -57,7 +64,7 @@ describe('SceneGridLayout', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
render(<scene.Component model={scene} />);
|
||||
renderWithProvider(<scene.Component model={scene} />);
|
||||
|
||||
expect(screen.queryAllByTestId('test-object')).toHaveLength(2);
|
||||
});
|
||||
@ -80,7 +87,7 @@ describe('SceneGridLayout', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
render(<scene.Component model={scene} />);
|
||||
renderWithProvider(<scene.Component model={scene} />);
|
||||
|
||||
expect(screen.queryAllByTestId('test-object')).toHaveLength(3);
|
||||
});
|
||||
|
@ -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<Props>) => {
|
||||
const store = configureStore();
|
||||
const props: Props = {
|
||||
navModel: {
|
||||
main: {
|
||||
@ -54,7 +59,11 @@ const setup = (propOverrides: Partial<Props>) => {
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
render(<ServiceAccountCreatePage {...props} />);
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<ServiceAccountCreatePage {...props} />
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('ServiceAccountCreatePage tests', () => {
|
||||
|
@ -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<Props>) => {
|
||||
const store = configureStore();
|
||||
const createServiceAccountTokenMock = jest.fn();
|
||||
const deleteServiceAccountMock = jest.fn();
|
||||
const deleteServiceAccountTokenMock = jest.fn();
|
||||
@ -49,7 +53,11 @@ const setup = (propOverrides: Partial<Props>) => {
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
const { rerender } = render(<ServiceAccountPageUnconnected {...props} />);
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<ServiceAccountPageUnconnected {...props} />
|
||||
</Provider>
|
||||
);
|
||||
return {
|
||||
rerender,
|
||||
props,
|
||||
|
@ -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<Props>) => {
|
||||
const store = configureStore();
|
||||
const changeQueryMock = jest.fn();
|
||||
const fetchACOptionsMock = jest.fn();
|
||||
const fetchServiceAccountsMock = jest.fn();
|
||||
@ -51,9 +55,13 @@ const setup = (propOverrides: Partial<Props>) => {
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
const { rerender } = render(<ServiceAccountsListPageUnconnected {...props} />);
|
||||
const { rerender } = render(
|
||||
<Provider store={store}>
|
||||
<ServiceAccountsListPageUnconnected {...props} />
|
||||
</Provider>
|
||||
);
|
||||
return {
|
||||
rerender,
|
||||
rerender: (element: JSX.Element) => rerender(<Provider store={store}>{element}</Provider>),
|
||||
props,
|
||||
changeQueryMock,
|
||||
fetchACOptionsMock,
|
||||
|
@ -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(<CreateTeam />);
|
||||
const store = configureStore();
|
||||
return render(
|
||||
<Provider store={store}>
|
||||
<CreateTeam />
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('Create team', () => {
|
||||
|
@ -1,9 +1,11 @@
|
||||
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 { contextSrv, User } from 'app/core/services/context_srv';
|
||||
|
||||
import { configureStore } from '../../store/configureStore';
|
||||
import { OrgRole, Team } from '../../types';
|
||||
|
||||
import { Props, TeamList } from './TeamList';
|
||||
@ -15,6 +17,7 @@ jest.mock('app/core/config', () => ({
|
||||
}));
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const store = configureStore();
|
||||
const props: Props = {
|
||||
teams: [] as Team[],
|
||||
noTeams: false,
|
||||
@ -37,7 +40,11 @@ const setup = (propOverrides?: object) => {
|
||||
|
||||
contextSrv.user = props.signedInUser;
|
||||
|
||||
render(<TeamList {...props} />);
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<TeamList {...props} />
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('TeamList', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user