The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx

206 lines
6.6 KiB

import { act, fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import { ReplaySubject } from 'rxjs';
import { EventBusSrv, getDefaultTimeRange, LoadingState, PanelData, PanelPlugin } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
import { setTimeSrv, TimeSrv } from '../services/TimeSrv';
import { DashboardModel, PanelModel } from '../state';
import { PanelStateWrapper, Props } from './PanelStateWrapper';
jest.mock('app/core/profiler', () => ({
profiler: {
renderingCompleted: jest.fn(),
},
}));
function setupTestContext(options: Partial<Props>) {
const mockStore = configureMockStore();
const store = mockStore({ dashboard: { panels: [] } });
const subject: ReplaySubject<PanelData> = new ReplaySubject<PanelData>();
const panelQueryRunner = {
getData: () => subject,
run: () => {
subject.next({ state: LoadingState.Done, series: [], timeRange: getDefaultTimeRange() });
},
} as unknown as PanelQueryRunner;
const timeSrv = {
timeRange: jest.fn(),
} as unknown as TimeSrv;
setTimeSrv(timeSrv);
const defaults: Props = {
panel: new PanelModel({
id: 123,
hasTitle: jest.fn(),
replaceVariables: jest.fn(),
events: new EventBusSrv(),
getQueryRunner: () => panelQueryRunner,
getOptions: jest.fn(),
getDisplayTitle: jest.fn(),
}),
dashboard: {
panelInitialized: jest.fn(),
getTimezone: () => 'browser',
events: new EventBusSrv(),
canAddAnnotations: jest.fn(),
canEditAnnotations: jest.fn(),
canDeleteAnnotations: jest.fn(),
meta: {
isPublic: false,
},
} as unknown as DashboardModel,
plugin: {
meta: { skipDataQuery: false },
panel: TestPanelComponent,
} as unknown as PanelPlugin,
isViewing: true,
isEditing: false,
isInView: false,
width: 100,
height: 100,
onInstanceStateChange: () => {},
};
const props = { ...defaults, ...options };
const { rerender } = render(
<Provider store={store}>
<PanelStateWrapper {...props} />
</Provider>
);
return { rerender, props, subject, store };
}
describe('PanelStateWrapper', () => {
describe('when the user scrolls by a panel so fast that it starts loading data but scrolls out of view', () => {
it('then it should load the panel successfully when scrolled into view again', () => {
const { rerender, props, subject, store } = setupTestContext({});
expect(screen.queryByText(/plugin panel to render/i)).not.toBeInTheDocument();
act(() => {
subject.next({ state: LoadingState.Loading, series: [], timeRange: getDefaultTimeRange() });
subject.next({ state: LoadingState.Done, series: [], timeRange: getDefaultTimeRange() });
});
const newProps = { ...props, isInView: true };
rerender(
<Provider store={store}>
<PanelStateWrapper {...newProps} />
</Provider>
);
expect(screen.getByText(/plugin panel to render/i)).toBeInTheDocument();
});
});
describe('when there are error(s)', () => {
[
{ errors: [{ message: 'boom!' }], expectedMessage: 'boom!' },
{
errors: [{ message: 'boom!' }, { message: 'boom2!' }],
expectedMessage: 'Multiple errors found. Click for more details',
},
].forEach((scenario) => {
it(`then it should show the error message: ${scenario.expectedMessage}`, async () => {
const { rerender, props, subject, store } = setupTestContext({});
act(() => {
subject.next({ state: LoadingState.Loading, series: [], timeRange: getDefaultTimeRange() });
subject.next({
state: LoadingState.Error,
series: [],
errors: scenario.errors,
timeRange: getDefaultTimeRange(),
});
});
const newProps = { ...props, isInView: true };
rerender(
<Provider store={store}>
<PanelStateWrapper {...newProps} />
</Provider>
);
const button = screen.getByTestId(selectors.components.Panels.Panel.status('error'));
expect(button).toBeInTheDocument();
await act(async () => {
fireEvent.focus(button);
});
expect(await screen.findByText(scenario.expectedMessage)).toBeInTheDocument();
});
});
});
describe('Panel row', () => {
it('should call query runner when it is not a row panel', async () => {
const subject: ReplaySubject<PanelData> = new ReplaySubject<PanelData>();
const panelQueryRunner = {
getData: () => subject,
run: jest.fn(),
} as unknown as PanelQueryRunner;
const options = {
panel: new PanelModel({
id: 123,
events: new EventBusSrv(),
getQueryRunner: () => panelQueryRunner,
getOptions: jest.fn(),
getDisplayTitle: jest.fn(),
}),
dashboard: {
panelInitialized: (panel: PanelModel) => panel.refresh(),
getTimezone: () => 'browser',
events: new EventBusSrv(),
canAddAnnotations: jest.fn(),
canEditAnnotations: jest.fn(),
canDeleteAnnotations: jest.fn(),
} as unknown as DashboardModel,
isInView: true,
};
const { props } = setupTestContext(options);
expect(props.panel.getQueryRunner().run).toHaveBeenCalled();
});
it('should not call query runner when it is a row panel', async () => {
const subject: ReplaySubject<PanelData> = new ReplaySubject<PanelData>();
const panelQueryRunner = {
getData: () => subject,
run: jest.fn(),
} as unknown as PanelQueryRunner;
const options = {
panel: new PanelModel({
id: 123,
events: new EventBusSrv(),
getQueryRunner: () => panelQueryRunner,
getOptions: jest.fn(),
getDisplayTitle: jest.fn(),
type: 'row',
}),
dashboard: {
panelInitialized: (panel: PanelModel) => panel.refresh(),
getTimezone: () => 'browser',
events: new EventBusSrv(),
canAddAnnotations: jest.fn(),
canEditAnnotations: jest.fn(),
canDeleteAnnotations: jest.fn(),
} as unknown as DashboardModel,
isInView: true,
};
const { props } = setupTestContext(options);
expect(props.panel.getQueryRunner().run).not.toHaveBeenCalled();
});
});
});
const TestPanelComponent = () => <div>Plugin Panel to Render</div>;