LibraryPanelsSearch.test.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. import { within } from '@testing-library/dom';
  2. import { render, screen, waitFor } from '@testing-library/react';
  3. import userEvent from '@testing-library/user-event';
  4. import React from 'react';
  5. import { PanelPluginMeta, PluginType } from '@grafana/data';
  6. import { backendSrv } from '../../../../core/services/backend_srv';
  7. import * as panelUtils from '../../../panel/state/util';
  8. import * as api from '../../state/api';
  9. import { LibraryElementKind, LibraryElementsSearchResult } from '../../types';
  10. import { LibraryPanelsSearch, LibraryPanelsSearchProps } from './LibraryPanelsSearch';
  11. jest.mock('@grafana/runtime', () => ({
  12. ...(jest.requireActual('@grafana/runtime') as unknown as object),
  13. config: {
  14. panels: {
  15. timeseries: {
  16. info: { logos: { small: '' } },
  17. name: 'Time Series',
  18. },
  19. },
  20. },
  21. }));
  22. jest.mock('debounce-promise', () => {
  23. const debounce = (fn: any) => {
  24. const debounced = () =>
  25. Promise.resolve([
  26. { label: 'General', value: { id: 0, title: 'General' } },
  27. { label: 'Folder1', value: { id: 1, title: 'Folder1' } },
  28. { label: 'Folder2', value: { id: 2, title: 'Folder2' } },
  29. ]);
  30. return debounced;
  31. };
  32. return debounce;
  33. });
  34. async function getTestContext(
  35. propOverrides: Partial<LibraryPanelsSearchProps> = {},
  36. searchResult: LibraryElementsSearchResult = { elements: [], perPage: 40, page: 1, totalCount: 0 }
  37. ) {
  38. jest.clearAllMocks();
  39. const pluginInfo: any = { logos: { small: '', large: '' } };
  40. const graph: PanelPluginMeta = {
  41. name: 'Graph',
  42. id: 'graph',
  43. info: pluginInfo,
  44. baseUrl: '',
  45. type: PluginType.panel,
  46. module: '',
  47. sort: 0,
  48. };
  49. const timeseries: PanelPluginMeta = {
  50. name: 'Time Series',
  51. id: 'timeseries',
  52. info: pluginInfo,
  53. baseUrl: '',
  54. type: PluginType.panel,
  55. module: '',
  56. sort: 1,
  57. };
  58. const getSpy = jest
  59. .spyOn(backendSrv, 'get')
  60. .mockResolvedValue({ sortOptions: [{ displaName: 'Desc', name: 'alpha-desc' }] });
  61. const getLibraryPanelsSpy = jest.spyOn(api, 'getLibraryPanels').mockResolvedValue(searchResult);
  62. const getAllPanelPluginMetaSpy = jest.spyOn(panelUtils, 'getAllPanelPluginMeta').mockReturnValue([graph, timeseries]);
  63. const props: LibraryPanelsSearchProps = {
  64. onClick: jest.fn(),
  65. };
  66. Object.assign(props, propOverrides);
  67. const { rerender } = render(<LibraryPanelsSearch {...props} />);
  68. await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalled());
  69. expect(getLibraryPanelsSpy).toHaveBeenCalledTimes(1);
  70. jest.clearAllMocks();
  71. return { rerender, getLibraryPanelsSpy, getSpy, getAllPanelPluginMetaSpy };
  72. }
  73. describe('LibraryPanelsSearch', () => {
  74. describe('when mounted with default options', () => {
  75. it('should show input filter and library panels view', async () => {
  76. await getTestContext();
  77. expect(screen.getByPlaceholderText(/search by name/i)).toBeInTheDocument();
  78. expect(screen.getByText(/no library panels found./i)).toBeInTheDocument();
  79. });
  80. describe('and user searches for library panel by name or description', () => {
  81. it('should call api with correct params', async () => {
  82. const { getLibraryPanelsSpy } = await getTestContext();
  83. await userEvent.type(screen.getByPlaceholderText(/search by name/i), 'a');
  84. await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalled());
  85. await waitFor(() =>
  86. expect(getLibraryPanelsSpy).toHaveBeenCalledWith({
  87. searchString: 'a',
  88. folderFilter: [],
  89. page: 0,
  90. typeFilter: [],
  91. perPage: 40,
  92. })
  93. );
  94. });
  95. });
  96. });
  97. describe('when mounted with showSort', () => {
  98. it('should show input filter and library panels view and sort', async () => {
  99. await getTestContext({ showSort: true });
  100. expect(screen.getByPlaceholderText(/search by name/i)).toBeInTheDocument();
  101. expect(screen.getByText(/no library panels found./i)).toBeInTheDocument();
  102. expect(screen.getByText(/sort \(default a–z\)/i)).toBeInTheDocument();
  103. });
  104. describe('and user changes sorting', () => {
  105. it('should call api with correct params', async () => {
  106. const { getLibraryPanelsSpy } = await getTestContext({ showSort: true });
  107. await userEvent.type(screen.getByText(/sort \(default a–z\)/i), 'Desc{enter}');
  108. await waitFor(() =>
  109. expect(getLibraryPanelsSpy).toHaveBeenCalledWith({
  110. searchString: '',
  111. sortDirection: 'alpha-desc',
  112. folderFilter: [],
  113. page: 0,
  114. typeFilter: [],
  115. perPage: 40,
  116. })
  117. );
  118. });
  119. });
  120. });
  121. describe('when mounted with showPanelFilter', () => {
  122. it('should show input filter and library panels view and panel filter', async () => {
  123. await getTestContext({ showPanelFilter: true });
  124. expect(screen.getByPlaceholderText(/search by name/i)).toBeInTheDocument();
  125. expect(screen.getByText(/no library panels found./i)).toBeInTheDocument();
  126. expect(screen.getByRole('combobox', { name: /panel type filter/i })).toBeInTheDocument();
  127. });
  128. describe('and user changes panel filter', () => {
  129. it('should call api with correct params', async () => {
  130. const { getLibraryPanelsSpy } = await getTestContext({ showPanelFilter: true });
  131. await userEvent.type(screen.getByRole('combobox', { name: /panel type filter/i }), 'Graph{enter}');
  132. await userEvent.type(screen.getByRole('combobox', { name: /panel type filter/i }), 'Time Series{enter}');
  133. await waitFor(() =>
  134. expect(getLibraryPanelsSpy).toHaveBeenCalledWith({
  135. searchString: '',
  136. folderFilter: [],
  137. page: 0,
  138. typeFilter: ['graph', 'timeseries'],
  139. perPage: 40,
  140. })
  141. );
  142. });
  143. });
  144. });
  145. describe('when mounted with showPanelFilter', () => {
  146. it('should show input filter and library panels view and folder filter', async () => {
  147. await getTestContext({ showFolderFilter: true });
  148. expect(screen.getByPlaceholderText(/search by name/i)).toBeInTheDocument();
  149. expect(screen.getByText(/no library panels found./i)).toBeInTheDocument();
  150. expect(screen.getByRole('combobox', { name: /folder filter/i })).toBeInTheDocument();
  151. });
  152. describe('and user changes folder filter', () => {
  153. it('should call api with correct params', async () => {
  154. const { getLibraryPanelsSpy } = await getTestContext({ showFolderFilter: true });
  155. await userEvent.click(screen.getByRole('combobox', { name: /folder filter/i }));
  156. await userEvent.type(screen.getByRole('combobox', { name: /folder filter/i }), '{enter}', {
  157. skipClick: true,
  158. });
  159. await waitFor(() =>
  160. expect(getLibraryPanelsSpy).toHaveBeenCalledWith({
  161. searchString: '',
  162. folderFilter: ['0'],
  163. page: 0,
  164. typeFilter: [],
  165. perPage: 40,
  166. })
  167. );
  168. });
  169. });
  170. });
  171. describe('when mounted without showSecondaryActions and there is one panel', () => {
  172. it('should show correct row and no delete button', async () => {
  173. await getTestContext(
  174. {},
  175. {
  176. page: 1,
  177. totalCount: 1,
  178. perPage: 40,
  179. elements: [
  180. {
  181. id: 1,
  182. name: 'Library Panel Name',
  183. kind: LibraryElementKind.Panel,
  184. uid: 'uid',
  185. description: 'Library Panel Description',
  186. folderId: 0,
  187. model: { type: 'timeseries', title: 'A title' },
  188. type: 'timeseries',
  189. orgId: 1,
  190. version: 1,
  191. meta: {
  192. folderName: 'General',
  193. folderUid: '',
  194. connectedDashboards: 0,
  195. created: '2021-01-01 12:00:00',
  196. createdBy: { id: 1, name: 'Admin', avatarUrl: '' },
  197. updated: '2021-01-01 12:00:00',
  198. updatedBy: { id: 1, name: 'Admin', avatarUrl: '' },
  199. },
  200. },
  201. ],
  202. }
  203. );
  204. const card = () => screen.getByLabelText(/plugin visualization item time series/i);
  205. expect(screen.queryByText(/no library panels found./i)).not.toBeInTheDocument();
  206. expect(card()).toBeInTheDocument();
  207. expect(within(card()).getByText(/library panel name/i)).toBeInTheDocument();
  208. expect(within(card()).getByText(/library panel description/i)).toBeInTheDocument();
  209. expect(within(card()).queryByLabelText(/delete button on panel type card/i)).not.toBeInTheDocument();
  210. });
  211. });
  212. describe('when mounted with showSecondaryActions and there is one panel', () => {
  213. it('should show correct row and delete button', async () => {
  214. await getTestContext(
  215. { showSecondaryActions: true },
  216. {
  217. page: 1,
  218. totalCount: 1,
  219. perPage: 40,
  220. elements: [
  221. {
  222. id: 1,
  223. name: 'Library Panel Name',
  224. kind: LibraryElementKind.Panel,
  225. uid: 'uid',
  226. description: 'Library Panel Description',
  227. folderId: 0,
  228. model: { type: 'timeseries', title: 'A title' },
  229. type: 'timeseries',
  230. orgId: 1,
  231. version: 1,
  232. meta: {
  233. folderName: 'General',
  234. folderUid: '',
  235. connectedDashboards: 0,
  236. created: '2021-01-01 12:00:00',
  237. createdBy: { id: 1, name: 'Admin', avatarUrl: '' },
  238. updated: '2021-01-01 12:00:00',
  239. updatedBy: { id: 1, name: 'Admin', avatarUrl: '' },
  240. },
  241. },
  242. ],
  243. }
  244. );
  245. const card = () => screen.getByLabelText(/plugin visualization item time series/i);
  246. expect(screen.queryByText(/no library panels found./i)).not.toBeInTheDocument();
  247. expect(card()).toBeInTheDocument();
  248. expect(within(card()).getByText(/library panel name/i)).toBeInTheDocument();
  249. expect(within(card()).getByText(/library panel description/i)).toBeInTheDocument();
  250. expect(within(card()).getByLabelText(/delete button on panel type card/i)).toBeInTheDocument();
  251. });
  252. });
  253. });