grafana/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx

145 lines
4.6 KiB
TypeScript

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.getByRole('button', {
name: selectors.components.Panels.Panel.headerCornerInfo('error'),
});
expect(button).toBeInTheDocument();
await act(async () => {
fireEvent.focus(button);
});
expect(await screen.findByText(scenario.expectedMessage)).toBeInTheDocument();
});
});
});
});
const TestPanelComponent = () => <div>Plugin Panel to Render</div>;