metricScratchpad.spec.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {render, screen, waitForElementToBeRemoved} from 'sentry-test/reactTestingLibrary';
  3. import type {PageFilters} from 'sentry/types/core';
  4. import type {MetricsQueryApiResponse} from 'sentry/types/metrics';
  5. import {VirtualMetricsContextProvider} from 'sentry/utils/metrics/virtualMetricsContext';
  6. import importedUsePageFilters from 'sentry/utils/usePageFilters';
  7. import {MetricsContextProvider} from 'sentry/views/metrics/context';
  8. import {MetricScratchpad} from 'sentry/views/metrics/scratchpad';
  9. jest.mock('sentry/components/metrics/chart/chart');
  10. jest.mock('echarts/core', () => {
  11. return {
  12. connect: jest.fn(),
  13. use: jest.fn(),
  14. };
  15. });
  16. jest.mock('sentry/utils/usePageFilters');
  17. const usePageFilters = jest.mocked(importedUsePageFilters);
  18. const makeFilterProps = (
  19. filters: Partial<PageFilters>
  20. ): ReturnType<typeof importedUsePageFilters> => {
  21. return {
  22. isReady: true,
  23. shouldPersist: true,
  24. desyncedFilters: new Set(),
  25. pinnedFilters: new Set(),
  26. selection: {
  27. projects: [1],
  28. environments: ['prod'],
  29. datetime: {start: new Date(), end: new Date(), period: '14d', utc: true},
  30. ...filters,
  31. },
  32. };
  33. };
  34. function renderMockRequests({
  35. orgSlug,
  36. projectId,
  37. metricsQueryApiResponse,
  38. }: {
  39. orgSlug: string;
  40. projectId: string;
  41. metricsQueryApiResponse?: Partial<MetricsQueryApiResponse>;
  42. }) {
  43. MockApiClient.addMockResponse({
  44. url: `/organizations/${orgSlug}/metrics/meta/`,
  45. body: [
  46. {
  47. type: 'd',
  48. name: 'duration',
  49. unit: 'millisecond',
  50. mri: 'd:transactions/duration@millisecond',
  51. operations: ['avg', 'count'],
  52. projectIds: [projectId],
  53. blockingStatus: [],
  54. },
  55. {
  56. type: 'd',
  57. name: 'duration',
  58. unit: 'millisecond',
  59. mri: 'd:spans/duration@millisecond',
  60. operations: ['avg', 'count'],
  61. projectIds: [projectId],
  62. blockingStatus: [],
  63. },
  64. ],
  65. });
  66. MockApiClient.addMockResponse({
  67. url: `/organizations/${orgSlug}/metrics/extraction-rules/`,
  68. method: 'GET',
  69. body: [
  70. {
  71. aggregates: ['count'],
  72. conditions: [{id: 102, value: '', mris: ['c:custom/span_attribute_102@none']}],
  73. createdById: 3142223,
  74. dateAdded: '2024-07-29T12:04:23.196785Z',
  75. dateUpdated: '2024-07-29T12:04:23.197008Z',
  76. projectId,
  77. spanAttribute: 'A',
  78. tags: ['release', 'environment'],
  79. unit: 'none',
  80. },
  81. ],
  82. });
  83. MockApiClient.addMockResponse({
  84. url: `/organizations/${orgSlug}/releases/stats/`,
  85. body: [],
  86. });
  87. MockApiClient.addMockResponse({
  88. url: `/organizations/${orgSlug}/metrics/query/`,
  89. method: 'POST',
  90. body: metricsQueryApiResponse ?? {
  91. data: [
  92. [
  93. {
  94. by: {},
  95. totals: 1000.0,
  96. series: [null, 1000.0],
  97. },
  98. ],
  99. ],
  100. meta: [
  101. [
  102. {
  103. name: 'aggregate_value',
  104. type: 'Float64',
  105. },
  106. {
  107. group_bys: [],
  108. order: 'DESC',
  109. limit: 715,
  110. has_more: false,
  111. unit_family: null,
  112. unit: null,
  113. scaling_factor: null,
  114. },
  115. ],
  116. ],
  117. start: '2024-04-25T00:00:00Z',
  118. end: '2024-08-01T00:00:00Z',
  119. intervals: ['2024-07-18T00:00:00Z', '2024-07-25T00:00:00Z'],
  120. },
  121. });
  122. }
  123. describe('metric Scratchpad', function () {
  124. it('render summary table if data', async function () {
  125. const {organization, project} = initializeOrg();
  126. usePageFilters.mockImplementation(() =>
  127. makeFilterProps({projects: [Number(project.id)]})
  128. );
  129. renderMockRequests({orgSlug: organization.slug, projectId: project.id});
  130. render(
  131. <MetricsContextProvider>
  132. <VirtualMetricsContextProvider>
  133. <MetricScratchpad />
  134. </VirtualMetricsContextProvider>
  135. </MetricsContextProvider>
  136. );
  137. await waitForElementToBeRemoved(() => screen.queryAllByTestId('loading-indicator'));
  138. expect(screen.getByTestId('summary-table')).toBeInTheDocument();
  139. });
  140. it('do NOT render summary table if there is no data', async function () {
  141. const {organization, project} = initializeOrg();
  142. usePageFilters.mockImplementation(() =>
  143. makeFilterProps({projects: [Number(project.id)]})
  144. );
  145. renderMockRequests({
  146. orgSlug: organization.slug,
  147. projectId: project.id,
  148. metricsQueryApiResponse: {
  149. data: [],
  150. meta: [],
  151. },
  152. });
  153. render(
  154. <MetricsContextProvider>
  155. <VirtualMetricsContextProvider>
  156. <MetricScratchpad />
  157. </VirtualMetricsContextProvider>
  158. </MetricsContextProvider>
  159. );
  160. await waitForElementToBeRemoved(() => screen.queryAllByTestId('loading-indicator'));
  161. expect(screen.queryByTestId('summary-table')).not.toBeInTheDocument();
  162. });
  163. });