Commit 645412f0 by hborchardt Committed by GitHub

Dashboard: Fix navigation from one SoloPanelPage to another one (#28578)

* Add test for SoloPanelPage.tsx

* Fix navigation from one SoloPanelPage to another one

The panel did not update because it assumed that the dashboard was already
fully loaded.
parent 00508295
import React from 'react';
import { render, screen } from '@testing-library/react';
import { SoloPanelPage, Props } from './SoloPanelPage';
import { Props as DashboardPanelProps } from '../dashgrid/DashboardPanel';
import { DashboardModel } from '../state';
import { DashboardRouteInfo } from 'app/types';
jest.mock('app/features/dashboard/components/DashboardSettings/SettingsCtrl', () => ({}));
jest.mock('app/features/dashboard/dashgrid/DashboardPanel', () => {
class DashboardPanel extends React.Component<DashboardPanelProps> {
render() {
// In this test we only check whether a new panel has arrived in the props
return <>{this.props.panel?.title}</>;
}
}
return { DashboardPanel };
});
interface ScenarioContext {
dashboard?: DashboardModel | null;
secondaryDashboard?: DashboardModel | null;
setDashboard: (overrides?: any, metaOverrides?: any) => void;
setSecondaryDashboard: (overrides?: any, metaOverrides?: any) => void;
mount: (propOverrides?: Partial<Props>) => void;
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: 'graph',
title: 'My graph',
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 soloPanelPageScenario(description: string, scenarioFn: (ctx: ScenarioContext) => void) {
describe(description, () => {
let setupFn: () => void;
const ctx: ScenarioContext = {
setup: fn => {
setupFn = fn;
},
setDashboard: (overrides?: any, metaOverrides?: any) => {
ctx.dashboard = getTestDashboard(overrides, metaOverrides);
},
setSecondaryDashboard: (overrides?: any, metaOverrides?: any) => {
ctx.secondaryDashboard = getTestDashboard(overrides, metaOverrides);
},
mount: (propOverrides?: Partial<Props>) => {
const props: Props = {
urlSlug: 'my-dash',
$scope: {},
urlUid: '11',
urlPanelId: '1',
$injector: {},
routeInfo: DashboardRouteInfo.Normal,
initDashboard: jest.fn(),
dashboard: null,
};
Object.assign(props, propOverrides);
ctx.dashboard = props.dashboard;
let { rerender } = render(<SoloPanelPage {...props} />);
// prop updates will be submitted by rerendering the same component with different props
ctx.rerender = (newProps: Partial<Props>) => {
Object.assign(props, newProps);
rerender(<SoloPanelPage {...props} />);
};
},
rerender: () => {
// will be replaced while mount() is called
},
};
beforeEach(() => {
setupFn();
});
scenarioFn(ctx);
});
}
describe('SoloPanelPage', () => {
soloPanelPageScenario('Given initial state', ctx => {
ctx.setup(() => {
ctx.mount();
});
it('Should render nothing', () => {
expect(screen.queryByText(/Loading/)).not.toBeNull();
});
});
soloPanelPageScenario('Dashboard init completed ', ctx => {
ctx.setup(() => {
ctx.mount();
ctx.setDashboard();
expect(ctx.dashboard).not.toBeNull();
// the componentDidMount will change the dashboard prop to the new dashboard
// emulate this by rerendering with new props
ctx.rerender({ dashboard: ctx.dashboard });
});
it('Should render dashboard grid', async () => {
// check if the panel title has arrived in the DashboardPanel mock
expect(screen.queryByText(/My graph/)).not.toBeNull();
});
});
soloPanelPageScenario('When user navigates to other SoloPanelPage', ctx => {
ctx.setup(() => {
ctx.mount();
ctx.setDashboard({ uid: 1, panels: [{ id: 1, type: 'graph', title: 'Panel 1' }] });
ctx.setSecondaryDashboard({ uid: 2, panels: [{ id: 1, type: 'graph', title: 'Panel 2' }] });
});
it('Should show other graph', () => {
// check that the title in the DashboardPanel has changed
ctx.rerender({ dashboard: ctx.dashboard });
expect(screen.queryByText(/Panel 1/)).not.toBeNull();
ctx.rerender({ dashboard: ctx.secondaryDashboard });
expect(screen.queryByText(/Panel 1/)).toBeNull();
expect(screen.queryByText(/Panel 2/)).not.toBeNull();
});
});
});
...@@ -13,7 +13,7 @@ import { initDashboard } from '../state/initDashboard'; ...@@ -13,7 +13,7 @@ import { initDashboard } from '../state/initDashboard';
import { StoreState, DashboardRouteInfo } from 'app/types'; import { StoreState, DashboardRouteInfo } from 'app/types';
import { PanelModel, DashboardModel } from 'app/features/dashboard/state'; import { PanelModel, DashboardModel } from 'app/features/dashboard/state';
interface Props { export interface Props {
urlPanelId: string; urlPanelId: string;
urlUid?: string; urlUid?: string;
urlSlug?: string; urlSlug?: string;
...@@ -25,7 +25,7 @@ interface Props { ...@@ -25,7 +25,7 @@ interface Props {
dashboard: DashboardModel | null; dashboard: DashboardModel | null;
} }
interface State { export interface State {
panel: PanelModel | null; panel: PanelModel | null;
notFound: boolean; notFound: boolean;
} }
...@@ -57,8 +57,8 @@ export class SoloPanelPage extends Component<Props, State> { ...@@ -57,8 +57,8 @@ export class SoloPanelPage extends Component<Props, State> {
return; return;
} }
// we just got the dashboard! // we just got a new dashboard
if (!prevProps.dashboard) { if (!prevProps.dashboard || prevProps.dashboard.uid !== dashboard.uid) {
const panelId = parseInt(urlPanelId, 10); const panelId = parseInt(urlPanelId, 10);
// need to expand parent row if this panel is inside a row // need to expand parent row if this panel is inside a row
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment