newWidgetBuilder.spec.tsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. });
  73. afterEach(() => PageFiltersStore.reset());
  74. it('renders', async function () {
  75. render(
  76. <WidgetBuilderV2
  77. isOpen
  78. onClose={onCloseMock}
  79. dashboard={DashboardFixture([])}
  80. dashboardFilters={{}}
  81. onSave={onSaveMock}
  82. />,
  83. {
  84. router,
  85. organization,
  86. }
  87. );
  88. expect(await screen.findByText('Create Custom Widget')).toBeInTheDocument();
  89. expect(await screen.findByLabelText('Close Widget Builder')).toBeInTheDocument();
  90. expect(await screen.findByRole('button', {name: 'All Projects'})).toBeInTheDocument();
  91. expect(await screen.findByRole('button', {name: 'All Envs'})).toBeInTheDocument();
  92. expect(await screen.findByRole('button', {name: '14D'})).toBeInTheDocument();
  93. expect(await screen.findByRole('button', {name: 'All Releases'})).toBeInTheDocument();
  94. expect(await screen.findByPlaceholderText('Name')).toBeInTheDocument();
  95. expect(await screen.findByText('+ Add Widget Description')).toBeInTheDocument();
  96. expect(await screen.findByLabelText('Dataset')).toHaveAttribute('role', 'radiogroup');
  97. expect(screen.getByText('Errors')).toBeInTheDocument();
  98. expect(screen.getByText('Transactions')).toBeInTheDocument();
  99. expect(screen.getByText('Spans')).toBeInTheDocument();
  100. expect(screen.getByText('Issues')).toBeInTheDocument();
  101. expect(screen.getByText('Releases')).toBeInTheDocument();
  102. expect(screen.getByText('Table')).toBeInTheDocument();
  103. // ensure the dropdown input has the default value 'table'
  104. expect(screen.getByDisplayValue('table')).toBeInTheDocument();
  105. expect(screen.getByPlaceholderText('Search')).toBeInTheDocument();
  106. // Test sort by selector for table display type
  107. expect(screen.getByText('Sort by')).toBeInTheDocument();
  108. expect(screen.getByText('High to low')).toBeInTheDocument();
  109. expect(screen.getByText(`Select a column\u{2026}`)).toBeInTheDocument();
  110. expect(await screen.findByPlaceholderText('Name')).toBeInTheDocument();
  111. expect(await screen.findByTestId('add-description')).toBeInTheDocument();
  112. expect(screen.getByLabelText('Widget panel')).toBeInTheDocument();
  113. await waitFor(() => {
  114. expect(screen.queryByText('Group by')).not.toBeInTheDocument();
  115. });
  116. });
  117. it('render the filter alias field and add filter button on chart widgets', async function () {
  118. const chartsRouter = RouterFixture({
  119. ...router,
  120. location: {
  121. ...router.location,
  122. query: {...router.location.query, displayType: 'line'},
  123. },
  124. });
  125. render(
  126. <WidgetBuilderV2
  127. isOpen
  128. onClose={onCloseMock}
  129. dashboard={DashboardFixture([])}
  130. dashboardFilters={{}}
  131. onSave={onSaveMock}
  132. />,
  133. {
  134. router: chartsRouter,
  135. organization,
  136. }
  137. );
  138. // see if alias field and add button are there
  139. expect(screen.getByPlaceholderText('Legend Alias')).toBeInTheDocument();
  140. expect(screen.getByText('Add Filter')).toBeInTheDocument();
  141. await waitFor(() => {
  142. expect(screen.queryByLabelText('Remove this filter')).not.toBeInTheDocument();
  143. });
  144. // add a field and see if delete buttons are there
  145. await userEvent.click(screen.getByText('Add Filter'));
  146. expect(screen.getAllByLabelText('Remove this filter')).toHaveLength(2);
  147. });
  148. it('does not render the filter alias field and add filter button on other widgets', async function () {
  149. render(
  150. <WidgetBuilderV2
  151. isOpen
  152. onClose={onCloseMock}
  153. dashboard={DashboardFixture([])}
  154. dashboardFilters={{}}
  155. onSave={onSaveMock}
  156. />,
  157. {
  158. router,
  159. organization,
  160. }
  161. );
  162. // see if alias field and add button are not there
  163. await waitFor(() => {
  164. expect(screen.queryByPlaceholderText('Legend Alias')).not.toBeInTheDocument();
  165. expect(screen.queryByText('Add Filter')).not.toBeInTheDocument();
  166. expect(screen.queryByLabelText('Remove this filter')).not.toBeInTheDocument();
  167. });
  168. });
  169. it('renders the group by field on chart widgets', async function () {
  170. const chartsRouter = RouterFixture({
  171. ...router,
  172. location: {
  173. ...router.location,
  174. query: {...router.location.query, displayType: 'line'},
  175. },
  176. });
  177. render(
  178. <WidgetBuilderV2
  179. isOpen
  180. onClose={onCloseMock}
  181. dashboard={DashboardFixture([])}
  182. dashboardFilters={{}}
  183. onSave={onSaveMock}
  184. />,
  185. {
  186. router: chartsRouter,
  187. organization,
  188. }
  189. );
  190. expect(await screen.findByText('Group by')).toBeInTheDocument();
  191. expect(await screen.findByText('Select group')).toBeInTheDocument();
  192. expect(await screen.findByText('Add Group')).toBeInTheDocument();
  193. });
  194. it('renders the limit sort by field on chart widgets', async function () {
  195. const chartsRouter = RouterFixture({
  196. ...router,
  197. location: {
  198. ...router.location,
  199. query: {...router.location.query, displayType: 'line'},
  200. },
  201. });
  202. render(
  203. <WidgetBuilderV2
  204. isOpen
  205. onClose={onCloseMock}
  206. dashboard={DashboardFixture([])}
  207. dashboardFilters={{}}
  208. onSave={onSaveMock}
  209. />,
  210. {
  211. router: chartsRouter,
  212. organization,
  213. }
  214. );
  215. expect(await screen.findByText('Limit to 5 results')).toBeInTheDocument();
  216. expect(await screen.findByText('High to low')).toBeInTheDocument();
  217. expect(await screen.findByText('(Required)')).toBeInTheDocument();
  218. });
  219. it('does not render sort by field on big number widgets', async function () {
  220. const bigNumberRouter = RouterFixture({
  221. ...router,
  222. location: {
  223. ...router.location,
  224. query: {...router.location.query, displayType: 'big_number'},
  225. },
  226. });
  227. render(
  228. <WidgetBuilderV2
  229. isOpen
  230. onClose={onCloseMock}
  231. dashboard={DashboardFixture([])}
  232. dashboardFilters={{}}
  233. onSave={onSaveMock}
  234. />,
  235. {
  236. router: bigNumberRouter,
  237. organization,
  238. }
  239. );
  240. await waitFor(() => {
  241. expect(screen.queryByText('Sort by')).not.toBeInTheDocument();
  242. });
  243. });
  244. });