newWidgetBuilder.spec.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import {DashboardFixture} from 'sentry-fixture/dashboard';
  2. import {RouterFixture} from 'sentry-fixture/routerFixture';
  3. import {initializeOrg} from 'sentry-test/initializeOrg';
  4. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  5. import OrganizationStore from 'sentry/stores/organizationStore';
  6. import PageFiltersStore from 'sentry/stores/pageFiltersStore';
  7. import ProjectsStore from 'sentry/stores/projectsStore';
  8. import WidgetBuilderV2 from 'sentry/views/dashboards/widgetBuilder/components/newWidgetBuilder';
  9. const {organization, projects, router} = initializeOrg({
  10. organization: {features: ['global-views', 'open-membership', 'dashboards-eap']},
  11. projects: [
  12. {id: '1', slug: 'project-1', isMember: true},
  13. {id: '2', slug: 'project-2', isMember: true},
  14. {id: '3', slug: 'project-3', isMember: false},
  15. ],
  16. router: {
  17. location: {
  18. pathname: '/organizations/org-slug/dashboard/1/',
  19. query: {project: '-1'},
  20. },
  21. params: {},
  22. },
  23. });
  24. describe('NewWidgetBuiler', function () {
  25. const onCloseMock = jest.fn();
  26. const onSaveMock = jest.fn();
  27. beforeEach(function () {
  28. OrganizationStore.init();
  29. PageFiltersStore.init();
  30. PageFiltersStore.onInitializeUrlState(
  31. {
  32. projects: [],
  33. environments: [],
  34. datetime: {start: null, end: null, period: '14d', utc: null},
  35. },
  36. new Set(['projects'])
  37. );
  38. OrganizationStore.onUpdate(organization, {replace: true});
  39. ProjectsStore.loadInitialData(projects);
  40. MockApiClient.addMockResponse({
  41. url: '/organizations/org-slug/releases/',
  42. body: [],
  43. });
  44. MockApiClient.addMockResponse({
  45. url: '/organizations/org-slug/dashboard/1/',
  46. body: [],
  47. });
  48. MockApiClient.addMockResponse({
  49. url: '/organizations/org-slug/issues/',
  50. body: [],
  51. });
  52. MockApiClient.addMockResponse({
  53. url: '/organizations/org-slug/events/',
  54. body: [],
  55. });
  56. MockApiClient.addMockResponse({
  57. url: '/organizations/org-slug/events-stats/',
  58. body: [],
  59. });
  60. MockApiClient.addMockResponse({
  61. url: '/organizations/org-slug/releases/stats/',
  62. body: [],
  63. });
  64. MockApiClient.addMockResponse({
  65. url: '/organizations/org-slug/spans/fields/',
  66. body: [],
  67. });
  68. MockApiClient.addMockResponse({
  69. url: '/organizations/org-slug/measurements-meta/',
  70. body: [],
  71. });
  72. MockApiClient.addMockResponse({
  73. url: '/organizations/org-slug/recent-searches/',
  74. });
  75. });
  76. afterEach(() => PageFiltersStore.reset());
  77. it('renders', async function () {
  78. render(
  79. <WidgetBuilderV2
  80. isOpen
  81. onClose={onCloseMock}
  82. dashboard={DashboardFixture([])}
  83. dashboardFilters={{}}
  84. onSave={onSaveMock}
  85. openWidgetTemplates={false}
  86. setOpenWidgetTemplates={jest.fn()}
  87. />,
  88. {
  89. router,
  90. organization,
  91. }
  92. );
  93. expect(await screen.findByText('Create Custom Widget')).toBeInTheDocument();
  94. expect(await screen.findByLabelText('Close Widget Builder')).toBeInTheDocument();
  95. expect(await screen.findByRole('button', {name: 'All Projects'})).toBeInTheDocument();
  96. expect(await screen.findByRole('button', {name: 'All Envs'})).toBeInTheDocument();
  97. expect(await screen.findByRole('button', {name: '14D'})).toBeInTheDocument();
  98. expect(await screen.findByRole('button', {name: 'All Releases'})).toBeInTheDocument();
  99. expect(await screen.findByPlaceholderText('Name')).toBeInTheDocument();
  100. expect(await screen.findByText('+ Add Widget Description')).toBeInTheDocument();
  101. expect(await screen.findByLabelText('Dataset')).toHaveAttribute('role', 'radiogroup');
  102. expect(screen.getByText('Errors')).toBeInTheDocument();
  103. expect(screen.getByText('Transactions')).toBeInTheDocument();
  104. expect(screen.getByText('Spans')).toBeInTheDocument();
  105. expect(screen.getByText('Issues')).toBeInTheDocument();
  106. expect(screen.getByText('Releases')).toBeInTheDocument();
  107. expect(screen.getByText('Table')).toBeInTheDocument();
  108. // ensure the dropdown input has the default value 'table'
  109. expect(screen.getByDisplayValue('table')).toBeInTheDocument();
  110. expect(screen.getByText('Filter')).toBeInTheDocument();
  111. expect(screen.getByLabelText('Create a search query')).toBeInTheDocument();
  112. // Test sort by selector for table display type
  113. expect(screen.getByText('Sort by')).toBeInTheDocument();
  114. expect(screen.getByText('High to low')).toBeInTheDocument();
  115. expect(screen.getByText(`Select a column\u{2026}`)).toBeInTheDocument();
  116. expect(await screen.findByPlaceholderText('Name')).toBeInTheDocument();
  117. expect(await screen.findByTestId('add-description')).toBeInTheDocument();
  118. expect(screen.getByLabelText('Widget panel')).toBeInTheDocument();
  119. await waitFor(() => {
  120. expect(screen.queryByText('Group by')).not.toBeInTheDocument();
  121. });
  122. });
  123. it('render the filter alias field and add filter button on chart widgets', async function () {
  124. const chartsRouter = RouterFixture({
  125. ...router,
  126. location: {
  127. ...router.location,
  128. query: {...router.location.query, displayType: 'line'},
  129. },
  130. });
  131. render(
  132. <WidgetBuilderV2
  133. isOpen
  134. onClose={onCloseMock}
  135. dashboard={DashboardFixture([])}
  136. dashboardFilters={{}}
  137. onSave={onSaveMock}
  138. openWidgetTemplates={false}
  139. setOpenWidgetTemplates={jest.fn()}
  140. />,
  141. {
  142. router: chartsRouter,
  143. organization,
  144. }
  145. );
  146. // see if alias field and add button are there
  147. expect(screen.getByPlaceholderText('Legend Alias')).toBeInTheDocument();
  148. expect(screen.getByText('Add Filter')).toBeInTheDocument();
  149. await waitFor(() => {
  150. expect(screen.queryByLabelText('Remove this filter')).not.toBeInTheDocument();
  151. });
  152. // add a field and see if delete buttons are there
  153. await userEvent.click(screen.getByText('Add Filter'));
  154. expect(screen.getAllByLabelText('Remove this filter')).toHaveLength(2);
  155. });
  156. it('does not render the filter alias field and add filter button on other widgets', async function () {
  157. render(
  158. <WidgetBuilderV2
  159. isOpen
  160. onClose={onCloseMock}
  161. dashboard={DashboardFixture([])}
  162. dashboardFilters={{}}
  163. onSave={onSaveMock}
  164. openWidgetTemplates={false}
  165. setOpenWidgetTemplates={jest.fn()}
  166. />,
  167. {
  168. router,
  169. organization,
  170. }
  171. );
  172. // see if alias field and add button are not there
  173. await waitFor(() => {
  174. expect(screen.queryByPlaceholderText('Legend Alias')).not.toBeInTheDocument();
  175. });
  176. expect(screen.queryByText('Add Filter')).not.toBeInTheDocument();
  177. expect(screen.queryByLabelText('Remove this filter')).not.toBeInTheDocument();
  178. });
  179. it('renders the group by field on chart widgets', async function () {
  180. const chartsRouter = RouterFixture({
  181. ...router,
  182. location: {
  183. ...router.location,
  184. query: {...router.location.query, displayType: 'line'},
  185. },
  186. });
  187. render(
  188. <WidgetBuilderV2
  189. isOpen
  190. onClose={onCloseMock}
  191. dashboard={DashboardFixture([])}
  192. dashboardFilters={{}}
  193. onSave={onSaveMock}
  194. openWidgetTemplates={false}
  195. setOpenWidgetTemplates={jest.fn()}
  196. />,
  197. {
  198. router: chartsRouter,
  199. organization,
  200. }
  201. );
  202. expect(await screen.findByText('Group by')).toBeInTheDocument();
  203. expect(await screen.findByText('Select group')).toBeInTheDocument();
  204. expect(await screen.findByText('Add Group')).toBeInTheDocument();
  205. });
  206. it('renders empty widget preview when no widget selected from templates', async function () {
  207. render(
  208. <WidgetBuilderV2
  209. isOpen
  210. onClose={onCloseMock}
  211. dashboard={DashboardFixture([])}
  212. dashboardFilters={{}}
  213. onSave={onSaveMock}
  214. openWidgetTemplates
  215. setOpenWidgetTemplates={jest.fn()}
  216. />,
  217. {router, organization}
  218. );
  219. expect(await screen.findByText('Add from Widget Library')).toBeInTheDocument();
  220. expect(await screen.findByText('Select a widget to preview')).toBeInTheDocument();
  221. });
  222. });