[Chore] Dashboard: Tests for dashboard's add content buttons and menu (#66233)

* add tests for empty dashboard page

* add tests for AddPanelButton

* export default components

* test +Add menu in dashboard page

* use userEvent instead of firing an event on the DOM itself

* fix test to match new analytic events
This commit is contained in:
Polina Boneva
2023-06-08 13:16:08 +03:00
committed by GitHub
parent 6d82962edf
commit 4db6679460
12 changed files with 321 additions and 25 deletions

View File

@@ -0,0 +1,48 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { defaultDashboard } from '@grafana/schema';
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
import AddPanelButton, { Props } from './AddPanelButton';
jest.mock('./AddPanelMenu', () => ({
...jest.requireActual('./AddPanelMenu'),
__esModule: true,
default: () => <div>Menu</div>,
}));
function setup(options?: Partial<Props>) {
const props = {
dashboard: createDashboardModelFixture(defaultDashboard),
};
const { rerender } = render(<AddPanelButton dashboard={props.dashboard} />);
return rerender;
}
beforeEach(() => {
jest.clearAllMocks();
});
it('renders button', () => {
setup();
expect(screen.getByRole('button', { name: 'Add' })).toBeInTheDocument();
});
it('renders button without menu when menu is not open', () => {
setup();
expect(screen.queryByText('Menu')).not.toBeInTheDocument();
});
it('renders button with menu when menu is open', async () => {
const user = userEvent.setup();
setup();
await user.click(screen.getByRole('button', { name: 'Add' }));
expect(screen.queryByText('Menu')).toBeInTheDocument();
});

View File

@@ -7,13 +7,13 @@ import { Dropdown, Button, useTheme2, Icon } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { DashboardModel } from 'app/features/dashboard/state';
import { AddPanelMenu } from './AddPanelMenu';
import AddPanelMenu from './AddPanelMenu';
interface Props {
export interface Props {
dashboard: DashboardModel;
}
export const AddPanelButton = ({ dashboard }: Props) => {
const AddPanelButton = ({ dashboard }: Props) => {
const styles = getStyles(useTheme2());
const [isMenuOpen, setIsMenuOpen] = useState(false);
@@ -29,7 +29,7 @@ export const AddPanelButton = ({ dashboard }: Props) => {
size="lg"
fill="text"
className={cx(styles.button, styles.buttonIcon, styles.buttonText)}
data-testid={selectors.components.PageToolbar.itemButton('Add panel button')}
data-testid={selectors.components.PageToolbar.itemButton('Add button')}
>
<Trans i18nKey="dashboard.toolbar.add">Add</Trans>
<Icon name={isMenuOpen ? 'angle-up' : 'angle-down'} size="lg" />
@@ -38,6 +38,8 @@ export const AddPanelButton = ({ dashboard }: Props) => {
);
};
export default AddPanelButton;
function getStyles(theme: GrafanaTheme2) {
return {
button: css({

View File

@@ -0,0 +1,138 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { PluginType } from '@grafana/data';
import { locationService, reportInteraction } from '@grafana/runtime';
import { defaultDashboard } from '@grafana/schema';
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
import {
onCreateNewPanel,
onCreateNewRow,
onAddLibraryPanel,
getCopiedPanelPlugin,
} from 'app/features/dashboard/utils/dashboard';
import AddPanelMenu from './AddPanelMenu';
jest.mock('app/types', () => ({
...jest.requireActual('app/types'),
useDispatch: () => jest.fn(),
useSelector: () => jest.fn(),
}));
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
locationService: {
partial: jest.fn(),
},
reportInteraction: jest.fn(),
config: {},
}));
jest.mock('app/features/dashboard/utils/dashboard', () => ({
onCreateNewPanel: jest.fn(),
onCreateNewRow: jest.fn(),
onAddLibraryPanel: jest.fn(),
getCopiedPanelPlugin: jest.fn(),
}));
function setup() {
const props = {
dashboard: createDashboardModelFixture(defaultDashboard),
};
const { rerender } = render(<AddPanelMenu dashboard={props.dashboard} />);
return rerender;
}
beforeEach(() => {
jest.clearAllMocks();
});
it('renders menu list with correct menu items', () => {
setup();
expect(screen.getByText('visualization', { exact: false })).toBeInTheDocument();
expect(screen.getByText('row', { exact: false })).toBeInTheDocument();
expect(screen.getByText('library', { exact: false })).toBeInTheDocument();
expect(screen.getByText('paste panel', { exact: false })).toBeInTheDocument();
});
it('renders with all buttons enabled except paste a panel', () => {
// getCopiedPanelPluginMock().mockReset();
setup();
expect(screen.getByText('visualization', { exact: false })).not.toBeDisabled();
expect(screen.getByText('row', { exact: false })).not.toBeDisabled();
expect(screen.getByText('library', { exact: false })).not.toBeDisabled();
expect(screen.getByText('paste panel', { exact: false })).toBeDisabled();
});
it('renders with all buttons enabled', () => {
(getCopiedPanelPlugin as jest.Mock).mockReturnValue({
id: 'someid',
name: 'nameofit',
type: PluginType.panel,
info: {
author: {
name: 'author name',
},
description: 'description',
links: [],
logos: {
small: 'small',
large: 'large',
},
updated: 'updated',
version: 'version',
},
module: 'module',
baseUrl: 'url',
sort: 2,
defaults: { gridPos: { w: 200, h: 100 }, title: 'some title' },
});
setup();
expect(screen.getByText('visualization', { exact: false })).not.toBeDisabled();
expect(screen.getByText('row', { exact: false })).not.toBeDisabled();
expect(screen.getByText('library', { exact: false })).not.toBeDisabled();
expect(screen.getByText('paste panel', { exact: false })).not.toBeDisabled();
});
it('creates new visualization when clicked on menu item Visualization', () => {
setup();
act(() => {
fireEvent.click(screen.getByRole('menuitem', { name: 'Visualization' }));
});
expect(reportInteraction).toHaveBeenCalledWith('dashboards_toolbar_add_clicked', { item: 'add_visualization' });
expect(locationService.partial).toHaveBeenCalled();
expect(onCreateNewPanel).toHaveBeenCalled();
});
it('creates new row when clicked on menu item Row', () => {
setup();
act(() => {
fireEvent.click(screen.getByRole('menuitem', { name: 'Row' }));
});
expect(reportInteraction).toHaveBeenCalledWith('dashboards_toolbar_add_clicked', { item: 'add_row' });
expect(locationService.partial).not.toHaveBeenCalled();
expect(onCreateNewRow).toHaveBeenCalled();
});
it('adds a library panel when clicked on menu item Import from library', () => {
setup();
act(() => {
fireEvent.click(screen.getByRole('menuitem', { name: 'Import from library' }));
});
expect(reportInteraction).toHaveBeenCalledWith('dashboards_toolbar_add_clicked', { item: 'import_from_library' });
expect(locationService.partial).not.toHaveBeenCalled();
expect(onAddLibraryPanel).toHaveBeenCalled();
});

View File

@@ -16,11 +16,11 @@ import { useDispatch, useSelector } from 'app/types';
import { setInitialDatasource } from '../../state/reducers';
interface Props {
export interface Props {
dashboard: DashboardModel;
}
export const AddPanelMenu = ({ dashboard }: Props) => {
const AddPanelMenu = ({ dashboard }: Props) => {
const copiedPanelPlugin = useMemo(() => getCopiedPanelPlugin(), []);
const dispatch = useDispatch();
const initialDatasource = useSelector((state) => state.dashboard.initialDatasource);
@@ -29,8 +29,8 @@ export const AddPanelMenu = ({ dashboard }: Props) => {
<Menu>
<Menu.Item
key="add-visualisation"
testId={selectors.pages.AddDashboard.itemButton('Add new visualization menu item')}
label={t('dashboard.add-menu.visualization', 'Visualization')}
testId={selectors.components.PageToolbar.itemButton('Add new visualization menu item')}
onClick={() => {
const id = onCreateNewPanel(dashboard, initialDatasource);
reportInteraction('dashboards_toolbar_add_clicked', { item: 'add_visualization' });
@@ -40,8 +40,8 @@ export const AddPanelMenu = ({ dashboard }: Props) => {
/>
<Menu.Item
key="add-row"
testId={selectors.pages.AddDashboard.itemButton('Add new row menu item')}
label={t('dashboard.add-menu.row', 'Row')}
testId={selectors.components.PageToolbar.itemButton('Add new row menu item')}
onClick={() => {
reportInteraction('dashboards_toolbar_add_clicked', { item: 'add_row' });
onCreateNewRow(dashboard);
@@ -49,8 +49,8 @@ export const AddPanelMenu = ({ dashboard }: Props) => {
/>
<Menu.Item
key="add-panel-lib"
testId={selectors.pages.AddDashboard.itemButton('Add new panel from panel library menu item')}
label={t('dashboard.add-menu.import', 'Import from library')}
testId={selectors.components.PageToolbar.itemButton('Add new panel from panel library menu item')}
onClick={() => {
reportInteraction('dashboards_toolbar_add_clicked', { item: 'import_from_library' });
onAddLibraryPanel(dashboard);
@@ -58,8 +58,8 @@ export const AddPanelMenu = ({ dashboard }: Props) => {
/>
<Menu.Item
key="add-panel-clipboard"
testId={selectors.pages.AddDashboard.itemButton('Add new panel from clipboard menu item')}
label={t('dashboard.add-menu.paste-panel', 'Paste panel')}
testId={selectors.components.PageToolbar.itemButton('Add new panel from clipboard menu item')}
onClick={() => {
reportInteraction('dashboards_toolbar_add_clicked', { item: 'paste_panel' });
onPasteCopiedPanel(dashboard, copiedPanelPlugin);
@@ -69,3 +69,5 @@ export const AddPanelMenu = ({ dashboard }: Props) => {
</Menu>
);
};
export default AddPanelMenu;