grafana_bak/public/app/features/dashboard/containers/PublicDashboardPage.test.tsx
2025-04-01 10:38:02 +09:00

335 lines
11 KiB
TypeScript

import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Route, Routes } from 'react-router-dom-v5-compat';
import { useEffectOnce } from 'react-use';
import { Props as AutoSizerProps } from 'react-virtualized-auto-sizer';
import { render } from 'test/test-utils';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { Dashboard, DashboardCursorSync, FieldConfigSource, Panel, ThresholdsMode } from '@grafana/schema/src';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
import * as appTypes from 'app/types';
import { DashboardInitPhase, DashboardMeta, DashboardRoutes } from 'app/types';
import { configureStore } from '../../../store/configureStore';
import { Props as LazyLoaderProps } from '../dashgrid/LazyLoader';
import { DashboardModel } from '../state/DashboardModel';
import { initDashboard } from '../state/initDashboard';
import PublicDashboardPage, { Props } from './PublicDashboardPage';
jest.mock('app/features/dashboard/dashgrid/LazyLoader', () => {
const LazyLoader = ({ children, onLoad }: Pick<LazyLoaderProps, 'children' | 'onLoad'>) => {
useEffectOnce(() => {
onLoad?.();
});
return <>{typeof children === 'function' ? children({ isInView: true }) : children}</>;
};
return { LazyLoader };
});
jest.mock('react-virtualized-auto-sizer', () => {
// The size of the children need to be small enough to be outside the view.
// So it does not trigger the query to be run by the PanelQueryRunner.
return ({ children }: AutoSizerProps) =>
children({
height: 1,
scaledHeight: 1,
scaledWidth: 1,
width: 1,
});
});
jest.mock('app/features/dashboard/state/initDashboard', () => ({
...jest.requireActual('app/features/dashboard/state/initDashboard'),
initDashboard: jest.fn(),
}));
jest.mock('app/types', () => ({
...jest.requireActual('app/types'),
useDispatch: () => jest.fn(),
}));
const setup = (propOverrides?: Partial<Props>, initialState?: Partial<appTypes.StoreState>) => {
const store = configureStore(initialState);
const props: Props = {
...getRouteComponentProps({
route: {
routeName: DashboardRoutes.Public,
path: '/public-dashboards/:accessToken',
component: () => null,
},
}),
};
Object.assign(props, propOverrides);
render(
<Routes>
<Route path="/public-dashboards/:accessToken" element={<PublicDashboardPage {...props} />} />
</Routes>,
{ store, historyOptions: { initialEntries: [`/public-dashboards/an-access-token`] } }
);
const wrappedRerender = (newProps: Partial<Props>) => {
Object.assign(props, newProps);
return render(
<Routes>
<Route path="/public-dashboards/:accessToken" element={<PublicDashboardPage {...props} />} />
</Routes>,
{ store, historyOptions: { initialEntries: [`/public-dashboards/an-access-token`] } }
);
};
return { rerender: wrappedRerender };
};
const selectors = e2eSelectors.components;
const publicDashboardSelector = e2eSelectors.pages.PublicDashboard;
const getTestDashboard = (overrides?: Partial<Dashboard>, metaOverrides?: Partial<DashboardMeta>): DashboardModel => {
const data: Dashboard = Object.assign(
{
title: 'My dashboard',
revision: 1,
editable: false,
graphTooltip: DashboardCursorSync.Off,
schemaVersion: 1,
timepicker: { hidden: true },
timezone: '',
panels: [
{
id: 1,
type: 'timeseries',
title: 'My panel title',
gridPos: { x: 0, y: 0, w: 1, h: 1 },
},
],
},
overrides
);
return new DashboardModel(data, metaOverrides);
};
const dashboardBase = {
getModel: getTestDashboard,
initError: null,
initPhase: DashboardInitPhase.Completed,
permissions: [],
};
describe('PublicDashboardPage', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('Should call initDashboard on mount', () => {
setup();
expect(initDashboard).toBeCalledWith({
fixUrl: false,
accessToken: 'an-access-token',
routeName: 'public-dashboard',
keybindingSrv: expect.anything(),
});
});
describe('Given a simple public dashboard', () => {
const newState = {
dashboard: dashboardBase,
};
it('Should render panels', async () => {
setup(undefined, newState);
expect(await screen.findByText('My panel title')).toBeInTheDocument();
});
it('Should update title', async () => {
setup(undefined, newState);
await waitFor(() => {
expect(document.title).toBe('My dashboard - Grafana');
});
});
it('Should not render neither time range nor refresh picker buttons', async () => {
setup(undefined, newState);
await waitFor(() => {
expect(screen.queryByTestId(selectors.TimePicker.openButton)).not.toBeInTheDocument();
expect(screen.queryByTestId(selectors.RefreshPicker.runButtonV2)).not.toBeInTheDocument();
expect(screen.queryByTestId(selectors.RefreshPicker.intervalButtonV2)).not.toBeInTheDocument();
});
});
it('Should not render paused or deleted screen', async () => {
setup(undefined, newState);
await waitFor(() => {
expect(screen.queryByTestId(publicDashboardSelector.NotAvailable.container)).not.toBeInTheDocument();
});
});
it('Should render panel with hover widget but without drag icon when panel title is undefined', async () => {
const fieldConfig: FieldConfigSource = {
defaults: {
thresholds: {
mode: ThresholdsMode.Absolute,
steps: [
{
color: 'green',
value: 1,
},
{
color: 'red',
value: 80,
},
],
},
},
overrides: [],
};
const panels: Panel[] = [
{
id: 1,
fieldConfig,
gridPos: {
h: 8,
w: 12,
x: 0,
y: 0,
},
options: {},
title: undefined,
type: 'timeseries',
repeatDirection: 'h',
transformations: [],
transparent: false,
},
];
const newState = {
dashboard: {
...dashboardBase,
getModel: () => getTestDashboard({ panels }),
},
};
setup(undefined, newState);
await waitFor(() => {
expect(screen.getByTestId(selectors.Panels.Panel.HoverWidget.container)).toBeInTheDocument();
});
await userEvent.hover(screen.getByTestId(selectors.Panels.Panel.HoverWidget.container));
expect(screen.queryByTestId(selectors.Panels.Panel.HoverWidget.dragIcon)).not.toBeInTheDocument();
});
it('Should render panel without hover widget when panel title is not undefined', async () => {
setup(undefined, newState);
await waitFor(() => {
expect(screen.queryByTestId(selectors.Panels.Panel.HoverWidget.container)).not.toBeInTheDocument();
});
});
});
describe('When public dashboard changes', () => {
it('Should init again', async () => {
const { rerender } = setup();
rerender({});
await waitFor(() => {
expect(initDashboard).toHaveBeenCalledTimes(2);
});
});
});
describe('Given a public dashboard with time range enabled', () => {
it('Should render time range and refresh picker buttons', async () => {
setup(undefined, {
dashboard: {
...dashboardBase,
getModel: () =>
getTestDashboard({
timepicker: { hidden: false, refresh_intervals: [] },
}),
},
});
expect(await screen.findByTestId(selectors.TimePicker.openButton)).toBeInTheDocument();
expect(screen.getByTestId(selectors.RefreshPicker.runButtonV2)).toBeInTheDocument();
expect(screen.getByTestId(selectors.RefreshPicker.intervalButtonV2)).toBeInTheDocument();
});
});
describe('Given paused public dashboard', () => {
it('Should render public dashboard paused screen', async () => {
setup(undefined, {
dashboard: {
...dashboardBase,
initError: {
message: 'Failed to fetch dashboard',
error: {
status: 403,
statusText: 'Forbidden',
data: {
statusCode: 403,
messageId: 'publicdashboards.notEnabled',
message: 'Dashboard paused',
},
config: {
method: 'GET',
url: 'api/public/dashboards/4615c835a4e441f09c94fb1b073e6d2e',
retry: 0,
headers: {
'X-Grafana-Org-Id': 1,
'X-Grafana-Device-Id': 'da48fad0e58ba327fd7d1e6bd17e9c63',
},
hideFromInspector: true,
},
},
},
getModel: () => getTestDashboard(undefined, { publicDashboardEnabled: false }),
},
});
await waitFor(() => {
expect(screen.queryByTestId(publicDashboardSelector.page)).not.toBeInTheDocument();
});
expect(screen.getByTestId(publicDashboardSelector.NotAvailable.title)).toBeInTheDocument();
expect(screen.getByTestId(publicDashboardSelector.NotAvailable.pausedDescription)).toBeInTheDocument();
});
});
describe('Given deleted public dashboard', () => {
it('Should render public dashboard deleted screen', async () => {
setup(undefined, {
dashboard: {
...dashboardBase,
initError: {
message: 'Failed to fetch dashboard',
error: {
status: 404,
statusText: 'Not Found',
data: {
statusCode: 404,
messageId: 'publicdashboards.notFound',
message: 'Dashboard not found',
},
config: {
method: 'GET',
url: 'api/public/dashboards/ce159fe139fc4d238a7d9c3ae33fb82b',
retry: 0,
hideFromInspector: true,
headers: {
'X-Grafana-Device-Id': 'da48fad0e58ba327fd7d1e6bd17e9c63',
},
},
},
},
getModel: () => getTestDashboard(undefined, {}),
},
});
await waitFor(() => {
expect(screen.queryByTestId(publicDashboardSelector.page)).not.toBeInTheDocument();
expect(screen.queryByTestId(publicDashboardSelector.NotAvailable.pausedDescription)).not.toBeInTheDocument();
});
expect(screen.getByTestId(publicDashboardSelector.NotAvailable.title)).toBeInTheDocument();
});
});
});