visualizationStep.spec.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import {TagsFixture} from 'sentry-fixture/tags';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  4. import ProjectsStore from 'sentry/stores/projectsStore';
  5. import type {Organization} from 'sentry/types/organization';
  6. import {DashboardWidgetSource} from 'sentry/views/dashboards/types';
  7. import WidgetBuilder from 'sentry/views/dashboards/widgetBuilder';
  8. jest.unmock('lodash/debounce');
  9. function mockRequests(orgSlug: Organization['slug']) {
  10. const eventsMock = MockApiClient.addMockResponse({
  11. url: `/organizations/${orgSlug}/events/`,
  12. method: 'GET',
  13. statusCode: 200,
  14. body: {
  15. meta: {},
  16. data: [],
  17. },
  18. });
  19. MockApiClient.addMockResponse({
  20. url: '/organizations/org-slug/tags/',
  21. method: 'GET',
  22. body: TagsFixture(),
  23. });
  24. MockApiClient.addMockResponse({
  25. url: '/organizations/org-slug/users/',
  26. body: [],
  27. });
  28. MockApiClient.addMockResponse({
  29. url: '/organizations/org-slug/projects/',
  30. method: 'GET',
  31. body: [],
  32. });
  33. MockApiClient.addMockResponse({
  34. url: '/organizations/org-slug/measurements-meta/',
  35. method: 'GET',
  36. body: {'measurements.custom.measurement': {functions: ['p99']}},
  37. });
  38. MockApiClient.addMockResponse({
  39. url: '/organizations/org-slug/metrics-compatibility/',
  40. method: 'GET',
  41. body: {
  42. incompatible_projects: [],
  43. compatible_projects: [1],
  44. },
  45. });
  46. MockApiClient.addMockResponse({
  47. url: '/organizations/org-slug/metrics-compatibility-sums/',
  48. method: 'GET',
  49. body: {
  50. sum: {
  51. metrics: 988803,
  52. metrics_null: 0,
  53. metrics_unparam: 132,
  54. },
  55. },
  56. });
  57. MockApiClient.addMockResponse({
  58. url: '/organizations/org-slug/releases/',
  59. body: [],
  60. });
  61. return {eventsMock};
  62. }
  63. describe('VisualizationStep', function () {
  64. const {organization, projects, router} = initializeOrg({
  65. organization: {
  66. features: ['dashboards-edit', 'global-views', 'dashboards-mep'],
  67. },
  68. router: {
  69. location: {
  70. query: {
  71. source: DashboardWidgetSource.DASHBOARDS,
  72. },
  73. },
  74. },
  75. });
  76. beforeEach(function () {
  77. ProjectsStore.loadInitialData(projects);
  78. });
  79. it('debounce works as expected and requests are not triggered often', async function () {
  80. const {eventsMock} = mockRequests(organization.slug);
  81. render(
  82. <WidgetBuilder
  83. route={{}}
  84. router={router}
  85. routes={router.routes}
  86. routeParams={router.params}
  87. location={router.location}
  88. dashboard={{
  89. id: 'new',
  90. title: 'Dashboard',
  91. createdBy: undefined,
  92. dateCreated: '2020-01-01T00:00:00.000Z',
  93. widgets: [],
  94. projects: [],
  95. filters: {},
  96. }}
  97. onSave={jest.fn()}
  98. params={{
  99. orgId: organization.slug,
  100. dashboardId: 'new',
  101. }}
  102. />,
  103. {
  104. router,
  105. organization,
  106. }
  107. );
  108. await waitFor(() => expect(eventsMock).toHaveBeenCalledTimes(1));
  109. await userEvent.type(await screen.findByPlaceholderText('Alias'), 'abc', {
  110. delay: null,
  111. });
  112. await waitFor(() => expect(eventsMock).toHaveBeenCalledTimes(1));
  113. });
  114. it('displays stored data alert', async function () {
  115. mockRequests(organization.slug);
  116. MockApiClient.addMockResponse({
  117. url: `/organizations/${organization.slug}/events/`,
  118. method: 'GET',
  119. statusCode: 200,
  120. body: {
  121. meta: {isMetricsData: false},
  122. data: [],
  123. },
  124. });
  125. render(
  126. <WidgetBuilder
  127. route={{}}
  128. router={router}
  129. routes={router.routes}
  130. routeParams={router.params}
  131. location={router.location}
  132. dashboard={{
  133. id: 'new',
  134. title: 'Dashboard',
  135. createdBy: undefined,
  136. dateCreated: '2020-01-01T00:00:00.000Z',
  137. widgets: [],
  138. projects: [],
  139. filters: {},
  140. }}
  141. onSave={jest.fn()}
  142. params={{
  143. orgId: organization.slug,
  144. dashboardId: 'new',
  145. }}
  146. />,
  147. {
  148. router,
  149. organization: {
  150. ...organization,
  151. features: [...organization.features, 'dynamic-sampling', 'mep-rollout-flag'],
  152. },
  153. }
  154. );
  155. await screen.findByText(/we've automatically adjusted your results/i);
  156. });
  157. it('uses release from URL params when querying', async function () {
  158. const {eventsMock} = mockRequests(organization.slug);
  159. render(
  160. <WidgetBuilder
  161. route={{}}
  162. router={router}
  163. routes={router.routes}
  164. routeParams={router.params}
  165. location={{
  166. ...router.location,
  167. query: {
  168. ...router.location.query,
  169. release: ['v1'],
  170. },
  171. }}
  172. dashboard={{
  173. id: 'new',
  174. title: 'Dashboard',
  175. createdBy: undefined,
  176. dateCreated: '2020-01-01T00:00:00.000Z',
  177. widgets: [],
  178. projects: [],
  179. filters: {},
  180. }}
  181. onSave={jest.fn()}
  182. params={{
  183. orgId: organization.slug,
  184. dashboardId: 'new',
  185. }}
  186. />,
  187. {
  188. router,
  189. organization,
  190. }
  191. );
  192. await waitFor(() =>
  193. expect(eventsMock).toHaveBeenCalledWith(
  194. '/organizations/org-slug/events/',
  195. expect.objectContaining({
  196. query: expect.objectContaining({query: ' release:"v1" '}),
  197. })
  198. )
  199. );
  200. });
  201. it('does not trigger an extra events request when adding a column', async function () {
  202. const {eventsMock} = mockRequests(organization.slug);
  203. render(
  204. <WidgetBuilder
  205. route={{}}
  206. router={router}
  207. routes={router.routes}
  208. routeParams={router.params}
  209. location={{
  210. ...router.location,
  211. query: {
  212. ...router.location.query,
  213. release: ['v1'],
  214. },
  215. }}
  216. dashboard={{
  217. id: 'new',
  218. title: 'Dashboard',
  219. createdBy: undefined,
  220. dateCreated: '2020-01-01T00:00:00.000Z',
  221. widgets: [],
  222. projects: [],
  223. filters: {},
  224. }}
  225. onSave={jest.fn()}
  226. params={{
  227. orgId: organization.slug,
  228. dashboardId: 'new',
  229. }}
  230. />,
  231. {
  232. router,
  233. organization,
  234. }
  235. );
  236. await userEvent.click(screen.getByText('Add a Column'));
  237. // Only called once on the initial render
  238. await waitFor(() => expect(eventsMock).toHaveBeenCalledTimes(1));
  239. });
  240. });