import 'whatwg-fetch'; import { render as rtlRender, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { HttpResponse, http } from 'msw'; import { setupServer, SetupServer } from 'msw/node'; import React, { ComponentProps } from 'react'; import AutoSizer from 'react-virtualized-auto-sizer'; import { TestProvider } from 'test/helpers/TestProvider'; import { selectors } from '@grafana/e2e-selectors'; import { contextSrv } from 'app/core/core'; import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps'; import { backendSrv } from 'app/core/services/backend_srv'; import BrowseDashboardsPage, { Props } from './BrowseDashboardsPage'; import { wellFormedTree } from './fixtures/dashboardsTreeItem.fixture'; import * as permissions from './permissions'; const [mockTree, { dashbdD, folderA, folderA_folderA }] = wellFormedTree(); jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), getBackendSrv: () => backendSrv, config: { ...jest.requireActual('@grafana/runtime').config, unifiedAlertingEnabled: true, }, })); jest.mock('react-virtualized-auto-sizer', () => { return { __esModule: true, default(props: ComponentProps) { return (
{props.children({ width: 800, scaledWidth: 800, scaledHeight: 600, height: 600, })}
); }, }; }); function render(...[ui, options]: Parameters) { const { rerender } = rtlRender( {ui} , options ); const wrappedRerender = (ui: React.ReactElement) => { rerender( {ui} ); }; return { rerender: wrappedRerender, }; } jest.mock('app/features/browse-dashboards/api/services', () => { const orig = jest.requireActual('app/features/browse-dashboards/api/services'); return { ...orig, listFolders(parentUID?: string) { const childrenForUID = mockTree .filter((v) => v.item.kind === 'folder' && v.item.parentUID === parentUID) .map((v) => v.item); return Promise.resolve(childrenForUID); }, listDashboards(parentUID?: string) { const childrenForUID = mockTree .filter((v) => v.item.kind === 'dashboard' && v.item.parentUID === parentUID) .map((v) => v.item); return Promise.resolve(childrenForUID); }, }; }); describe('browse-dashboards BrowseDashboardsPage', () => { let props: Props; let server: SetupServer; const mockPermissions = { canCreateDashboards: true, canEditDashboards: true, canCreateFolders: true, canDeleteFolders: true, canEditFolders: true, canViewPermissions: true, canSetPermissions: true, }; beforeAll(() => { server = setupServer( http.get('/api/folders/:uid', () => { return HttpResponse.json({ title: folderA.item.title, uid: folderA.item.uid, }); }), http.get('/api/search', () => { return HttpResponse.json({}); }), http.get('/api/search/sorting', () => { return HttpResponse.json({ sortOptions: [], }); }) ); server.listen(); }); afterAll(() => { server.close(); }); beforeEach(() => { props = { ...getRouteComponentProps(), }; jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => mockPermissions); jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); }); afterEach(() => { jest.restoreAllMocks(); server.resetHandlers(); }); describe('at the root level', () => { it('displays "Dashboards" as the page title', async () => { render(); expect(await screen.findByRole('heading', { name: 'Dashboards' })).toBeInTheDocument(); }); it('displays a search input', async () => { render(); expect(await screen.findByPlaceholderText('Search for dashboards and folders')).toBeInTheDocument(); }); it('shows the "New" button', async () => { render(); expect(await screen.findByRole('button', { name: 'New' })).toBeInTheDocument(); }); it('does not show the "New" button if the user does not have permissions', async () => { jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => { return { ...mockPermissions, canCreateDashboards: false, canCreateFolders: false, }; }); render(); expect(await screen.findByRole('heading', { name: 'Dashboards' })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'New' })).not.toBeInTheDocument(); }); it('does not show "Folder actions"', async () => { render(); expect(await screen.findByRole('heading', { name: 'Dashboards' })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument(); }); it('does not show an "Edit title" button', async () => { render(); expect(await screen.findByRole('heading', { name: 'Dashboards' })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Edit title' })).not.toBeInTheDocument(); }); it('does not show any tabs', async () => { render(); expect(await screen.findByRole('heading', { name: 'Dashboards' })).toBeInTheDocument(); expect(screen.queryByRole('tab', { name: 'Tab Dashboards' })).not.toBeInTheDocument(); expect(screen.queryByRole('tab', { name: 'Tab Panels' })).not.toBeInTheDocument(); expect(screen.queryByRole('tab', { name: 'Tab Alert rules' })).not.toBeInTheDocument(); }); it('displays the filters and hides the actions initially', async () => { render(); await screen.findByPlaceholderText('Search for dashboards and folders'); expect(await screen.findByText('Sort')).toBeInTheDocument(); expect(await screen.findByText('Filter by tag')).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Move' })).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Delete' })).not.toBeInTheDocument(); }); it('selecting an item hides the filters and shows the actions instead', async () => { render(); const checkbox = await screen.findByTestId(selectors.pages.BrowseDashboards.table.checkbox(dashbdD.item.uid)); await userEvent.click(checkbox); // Check the filters are now hidden expect(screen.queryByText('Filter by tag')).not.toBeInTheDocument(); expect(screen.queryByText('Sort')).not.toBeInTheDocument(); // Check the actions are now visible expect(screen.getByRole('button', { name: 'Move' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Delete' })).toBeInTheDocument(); }); it('navigating into a child item resets the selected state', async () => { const { rerender } = render(); const checkbox = await screen.findByTestId(selectors.pages.BrowseDashboards.table.checkbox(folderA.item.uid)); await userEvent.click(checkbox); // Check the actions are now visible expect(screen.getByRole('button', { name: 'Move' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Delete' })).toBeInTheDocument(); const updatedProps = { ...props }; updatedProps.match.params = { uid: folderA.item.uid }; rerender(); // Check the filters are now visible again expect(await screen.findByText('Filter by tag')).toBeInTheDocument(); expect(await screen.findByText('Sort')).toBeInTheDocument(); // Check the actions are no longer visible expect(screen.queryByRole('button', { name: 'Move' })).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Delete' })).not.toBeInTheDocument(); }); }); describe('for a child folder', () => { beforeEach(() => { props.match.params = { uid: folderA.item.uid }; }); it('shows the folder name as the page title', async () => { render(); expect(await screen.findByRole('heading', { name: folderA.item.title })).toBeInTheDocument(); }); it('displays a search input', async () => { render(); expect(await screen.findByPlaceholderText('Search for dashboards and folders')).toBeInTheDocument(); }); it('shows the "New" button', async () => { render(); expect(await screen.findByRole('button', { name: 'New' })).toBeInTheDocument(); }); it('does not show the "New" button if the user does not have permissions', async () => { jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => { return { ...mockPermissions, canCreateDashboards: false, canCreateFolders: false, }; }); render(); expect(await screen.findByRole('heading', { name: folderA.item.title })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'New' })).not.toBeInTheDocument(); }); it('shows the "Folder actions" button', async () => { render(); expect(await screen.findByRole('button', { name: 'Folder actions' })).toBeInTheDocument(); }); it('does not show the "Folder actions" button if the user does not have permissions', async () => { jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => { return { ...mockPermissions, canDeleteFolders: false, canEditFolders: false, canSetPermissions: false, canViewPermissions: false, }; }); render(); expect(await screen.findByRole('heading', { name: folderA.item.title })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Folder actions' })).not.toBeInTheDocument(); }); it('shows an "Edit title" button', async () => { render(); expect(await screen.findByRole('button', { name: 'Edit title' })).toBeInTheDocument(); }); it('does not show the "Edit title" button if the user does not have permissions', async () => { jest.spyOn(permissions, 'getFolderPermissions').mockImplementation(() => { return { ...mockPermissions, canEditFolders: false, }; }); render(); expect(await screen.findByRole('heading', { name: folderA.item.title })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Edit title' })).not.toBeInTheDocument(); }); it('displays all the folder tabs and shows the "Dashboards" tab as selected', async () => { render(); expect(await screen.findByRole('tab', { name: 'Tab Dashboards' })).toBeInTheDocument(); expect(await screen.findByRole('tab', { name: 'Tab Dashboards' })).toHaveAttribute('aria-selected', 'true'); expect(await screen.findByRole('tab', { name: 'Tab Panels' })).toBeInTheDocument(); expect(await screen.findByRole('tab', { name: 'Tab Panels' })).toHaveAttribute('aria-selected', 'false'); expect(await screen.findByRole('tab', { name: 'Tab Alert rules' })).toBeInTheDocument(); expect(await screen.findByRole('tab', { name: 'Tab Alert rules' })).toHaveAttribute('aria-selected', 'false'); }); it('displays the filters and hides the actions initially', async () => { render(); await screen.findByPlaceholderText('Search for dashboards and folders'); expect(await screen.findByText('Sort')).toBeInTheDocument(); expect(await screen.findByText('Filter by tag')).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Move' })).not.toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Delete' })).not.toBeInTheDocument(); }); it('selecting an item hides the filters and shows the actions instead', async () => { render(); const checkbox = await screen.findByTestId( selectors.pages.BrowseDashboards.table.checkbox(folderA_folderA.item.uid) ); await userEvent.click(checkbox); // Check the filters are now hidden expect(screen.queryByText('Filter by tag')).not.toBeInTheDocument(); expect(screen.queryByText('Sort')).not.toBeInTheDocument(); // Check the actions are now visible expect(screen.getByRole('button', { name: 'Move' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Delete' })).toBeInTheDocument(); }); }); });