diff --git a/public/app/core/components/NavBar/NavBarItem.test.tsx b/public/app/core/components/NavBar/NavBarItem.test.tsx index 49a47820b9a..1103f209be5 100644 --- a/public/app/core/components/NavBar/NavBarItem.test.tsx +++ b/public/app/core/components/NavBar/NavBarItem.test.tsx @@ -1,8 +1,11 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { BrowserRouter } from 'react-router-dom'; +import { locationUtil } from '@grafana/data'; +import { config, setLocationService } from '@grafana/runtime'; + import NavBarItem, { Props } from './NavBarItem'; -import userEvent from '@testing-library/user-event'; const onClickMock = jest.fn(); const defaults: Props = { @@ -17,8 +20,13 @@ const defaults: Props = { }, }; -function getTestContext(overrides: Partial = {}) { +function getTestContext(overrides: Partial = {}, subUrl = '') { jest.clearAllMocks(); + config.appSubUrl = subUrl; + locationUtil.initialize({ config, getTimeRangeForUrl: jest.fn(), getVariablesUrlParams: jest.fn() }); + const pushMock = jest.fn(); + const locationService: any = { push: pushMock }; + setLocationService(locationService); const props = { ...defaults, ...overrides }; const { rerender } = render( @@ -27,7 +35,7 @@ function getTestContext(overrides: Partial = {}) { ); - return { rerender }; + return { rerender, pushMock }; } describe('NavBarItem', () => { @@ -140,5 +148,56 @@ describe('NavBarItem', () => { expect(screen.getAllByRole('menuitem')[2]).toHaveAttribute('tabIndex', '-1'); }); }); + + describe('when appSubUrl is configured and user clicks on menuitem link', () => { + it('then location service should be called with correct url', async () => { + const { pushMock } = getTestContext( + { + link: { + ...defaults.link, + url: 'https://www.grafana.com', + children: [{ text: 'New', url: '/grafana/dashboard/new', children: [] }], + }, + }, + '/grafana' + ); + + userEvent.hover(screen.getByRole('link')); + await waitFor(() => { + expect(screen.getByText('Parent Node')).toBeInTheDocument(); + expect(screen.getByText('New')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByText('New')); + await waitFor(() => { + expect(pushMock).toHaveBeenCalledTimes(1); + expect(pushMock).toHaveBeenCalledWith('/dashboard/new'); + }); + }); + }); + + describe('when appSubUrl is not configured and user clicks on menuitem link', () => { + it('then location service should be called with correct url', async () => { + const { pushMock } = getTestContext({ + link: { + ...defaults.link, + url: 'https://www.grafana.com', + children: [{ text: 'New', url: '/grafana/dashboard/new', children: [] }], + }, + }); + + userEvent.hover(screen.getByRole('link')); + await waitFor(() => { + expect(screen.getByText('Parent Node')).toBeInTheDocument(); + expect(screen.getByText('New')).toBeInTheDocument(); + }); + + userEvent.click(screen.getByText('New')); + await waitFor(() => { + expect(pushMock).toHaveBeenCalledTimes(1); + expect(pushMock).toHaveBeenCalledWith('/grafana/dashboard/new'); + }); + }); + }); }); }); diff --git a/public/app/core/components/NavBar/NavBarItem.tsx b/public/app/core/components/NavBar/NavBarItem.tsx index c049451ca70..7304e8a8e8a 100644 --- a/public/app/core/components/NavBar/NavBarItem.tsx +++ b/public/app/core/components/NavBar/NavBarItem.tsx @@ -1,7 +1,7 @@ import React, { ReactNode } from 'react'; import { Item } from '@react-stately/collections'; import { css, cx } from '@emotion/css'; -import { GrafanaTheme2, NavMenuItemType, NavModelItem } from '@grafana/data'; +import { GrafanaTheme2, locationUtil, NavMenuItemType, NavModelItem } from '@grafana/data'; import { IconName, useTheme2 } from '@grafana/ui'; import { locationService } from '@grafana/runtime'; @@ -50,7 +50,7 @@ const NavBarItem = ({ } if (!target && url.startsWith('/')) { - locationService.push(url); + locationService.push(locationUtil.stripBaseFromUrl(url)); } else { window.open(url, target); }