123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- import { render, screen } from '@testing-library/react';
- import React from 'react';
- import { Provider } from 'react-redux';
- import { Router } from 'react-router-dom';
- import { useEffectOnce } from 'react-use';
- import { AutoSizerProps } from 'react-virtualized-auto-sizer';
- import { mockToolkitActionCreator } from 'test/core/redux/mocks';
- import { createTheme } from '@grafana/data';
- import { selectors } from '@grafana/e2e-selectors';
- import { locationService, setDataSourceSrv } from '@grafana/runtime';
- import { notifyApp } from 'app/core/actions';
- import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
- import { DashboardInitPhase, DashboardRoutes } from 'app/types';
- import { configureStore } from '../../../store/configureStore';
- import { Props as LazyLoaderProps } from '../dashgrid/LazyLoader';
- import { setDashboardSrv } from '../services/DashboardSrv';
- import { DashboardModel } from '../state';
- import { Props, UnthemedDashboardPage } from './DashboardPage';
- 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('app/features/dashboard/components/DashboardSettings/GeneralSettings', () => {
- class GeneralSettings extends React.Component<{}, {}> {
- render() {
- return <>general settings</>;
- }
- }
- return { GeneralSettings };
- });
- jest.mock('app/features/query/components/QueryGroup', () => {
- return {
- QueryGroup: () => null,
- };
- });
- jest.mock('app/core/core', () => ({
- appEvents: {
- subscribe: () => {
- return { unsubscribe: () => {} };
- },
- },
- }));
- 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, width: 1 });
- });
- // the mock below gets rid of this warning from recompose:
- // Warning: React.createFactory() is deprecated and will be removed in a future major release. Consider using JSX or use React.createElement() directly instead.
- jest.mock('@jaegertracing/jaeger-ui-components', () => ({}));
- interface ScenarioContext {
- dashboard?: DashboardModel | null;
- container?: HTMLElement;
- mount: (propOverrides?: Partial<Props>) => void;
- unmount: () => void;
- props: Props;
- rerender: (propOverrides?: Partial<Props>) => void;
- setup: (fn: () => void) => void;
- }
- function getTestDashboard(overrides?: any, metaOverrides?: any): DashboardModel {
- const data = Object.assign(
- {
- title: 'My dashboard',
- panels: [
- {
- id: 1,
- type: 'timeseries',
- title: 'My panel title',
- gridPos: { x: 0, y: 0, w: 1, h: 1 },
- },
- ],
- },
- overrides
- );
- const meta = Object.assign({ canSave: true, canEdit: true }, metaOverrides);
- return new DashboardModel(data, meta);
- }
- function dashboardPageScenario(description: string, scenarioFn: (ctx: ScenarioContext) => void) {
- describe(description, () => {
- let setupFn: () => void;
- const ctx: ScenarioContext = {
- setup: (fn) => {
- setupFn = fn;
- },
- mount: (propOverrides?: Partial<Props>) => {
- const store = configureStore();
- const props: Props = {
- ...getRouteComponentProps({
- match: { params: { slug: 'my-dash', uid: '11' } } as any,
- route: { routeName: DashboardRoutes.Normal } as any,
- }),
- initPhase: DashboardInitPhase.NotStarted,
- initError: null,
- initDashboard: jest.fn(),
- notifyApp: mockToolkitActionCreator(notifyApp),
- cleanUpDashboardAndVariables: jest.fn(),
- cancelVariables: jest.fn(),
- templateVarsChangedInUrl: jest.fn(),
- dashboard: null,
- theme: createTheme(),
- };
- Object.assign(props, propOverrides);
- ctx.props = props;
- ctx.dashboard = props.dashboard;
- const { container, rerender, unmount } = render(
- <Provider store={store}>
- <Router history={locationService.getHistory()}>
- <UnthemedDashboardPage {...props} />
- </Router>
- </Provider>
- );
- ctx.container = container;
- ctx.rerender = (newProps?: Partial<Props>) => {
- Object.assign(props, newProps);
- rerender(
- <Provider store={store}>
- <Router history={locationService.getHistory()}>
- <UnthemedDashboardPage {...props} />
- </Router>
- </Provider>
- );
- };
- ctx.unmount = unmount;
- },
- props: {} as Props,
- rerender: () => {},
- unmount: () => {},
- };
- beforeEach(() => {
- setupFn();
- });
- scenarioFn(ctx);
- });
- }
- describe('DashboardPage', () => {
- dashboardPageScenario('Given initial state', (ctx) => {
- ctx.setup(() => {
- ctx.mount();
- });
- it('Should call initDashboard on mount', () => {
- expect(ctx.props.initDashboard).toBeCalledWith({
- fixUrl: true,
- routeName: 'normal-dashboard',
- urlSlug: 'my-dash',
- urlUid: '11',
- });
- });
- });
- dashboardPageScenario('Given a simple dashboard', (ctx) => {
- ctx.setup(() => {
- ctx.mount();
- ctx.rerender({ dashboard: getTestDashboard() });
- });
- it('Should render panels', () => {
- expect(screen.getByText('My panel title')).toBeInTheDocument();
- });
- it('Should update title', () => {
- expect(document.title).toBe('My dashboard - Grafana');
- });
- });
- dashboardPageScenario('When going into view mode', (ctx) => {
- ctx.setup(() => {
- setDataSourceSrv({
- get: jest.fn().mockResolvedValue({ getRef: jest.fn(), query: jest.fn().mockResolvedValue([]) }),
- getInstanceSettings: jest.fn().mockReturnValue({ meta: {} }),
- getList: jest.fn(),
- reload: jest.fn(),
- });
- setDashboardSrv({
- getCurrent: () => getTestDashboard(),
- } as any);
- ctx.mount({
- dashboard: getTestDashboard(),
- queryParams: { viewPanel: '1' },
- });
- });
- it('Should render panel in view mode', () => {
- expect(ctx.dashboard?.panelInView).toBeDefined();
- expect(ctx.dashboard?.panels[0].isViewing).toBe(true);
- });
- it('Should reset state when leaving', () => {
- ctx.rerender({ queryParams: {} });
- expect(ctx.dashboard?.panelInView).toBeUndefined();
- expect(ctx.dashboard?.panels[0].isViewing).toBe(false);
- });
- });
- dashboardPageScenario('When going into edit mode', (ctx) => {
- ctx.setup(() => {
- ctx.mount({
- dashboard: getTestDashboard(),
- queryParams: { editPanel: '1' },
- });
- });
- it('Should render panel in edit mode', () => {
- expect(ctx.dashboard?.panelInEdit).toBeDefined();
- });
- it('Should render panel editor', () => {
- expect(screen.getByTitle('Apply changes and go back to dashboard')).toBeInTheDocument();
- });
- it('Should reset state when leaving', () => {
- ctx.rerender({ queryParams: {} });
- expect(screen.queryByTitle('Apply changes and go back to dashboard')).not.toBeInTheDocument();
- });
- });
- dashboardPageScenario('When dashboard unmounts', (ctx) => {
- ctx.setup(() => {
- ctx.mount();
- ctx.rerender({ dashboard: getTestDashboard() });
- ctx.unmount();
- });
- it('Should call close action', () => {
- expect(ctx.props.cleanUpDashboardAndVariables).toHaveBeenCalledTimes(1);
- });
- });
- dashboardPageScenario('When dashboard changes', (ctx) => {
- ctx.setup(() => {
- ctx.mount();
- ctx.rerender({ dashboard: getTestDashboard() });
- ctx.rerender({
- match: {
- params: { uid: 'new-uid' },
- } as any,
- dashboard: getTestDashboard({ title: 'Another dashboard' }),
- });
- });
- it('Should call clean up action and init', () => {
- expect(ctx.props.cleanUpDashboardAndVariables).toHaveBeenCalledTimes(1);
- expect(ctx.props.initDashboard).toHaveBeenCalledTimes(2);
- });
- });
- dashboardPageScenario('No kiosk mode tv', (ctx) => {
- ctx.setup(() => {
- ctx.mount({ dashboard: getTestDashboard() });
- ctx.rerender({ dashboard: ctx.dashboard });
- });
- it('should render dashboard page toolbar and submenu', () => {
- expect(screen.queryAllByTestId(selectors.pages.Dashboard.DashNav.navV2)).toHaveLength(1);
- expect(screen.queryAllByLabelText(selectors.pages.Dashboard.SubMenu.submenu)).toHaveLength(1);
- });
- });
- dashboardPageScenario('When in full kiosk mode', (ctx) => {
- ctx.setup(() => {
- locationService.partial({ kiosk: true });
- ctx.mount({
- queryParams: {},
- dashboard: getTestDashboard(),
- });
- ctx.rerender({ dashboard: ctx.dashboard });
- });
- it('should not render page toolbar and submenu', () => {
- expect(screen.queryAllByTestId(selectors.pages.Dashboard.DashNav.navV2)).toHaveLength(0);
- expect(screen.queryAllByLabelText(selectors.pages.Dashboard.SubMenu.submenu)).toHaveLength(0);
- });
- });
- });
|