visualize.spec.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import {LocationFixture} from 'sentry-fixture/locationFixture';
  2. import {OrganizationFixture} from 'sentry-fixture/organization';
  3. import {RouterFixture} from 'sentry-fixture/routerFixture';
  4. import {render, screen, userEvent, within} from 'sentry-test/reactTestingLibrary';
  5. import type {TagCollection} from 'sentry/types/group';
  6. import useCustomMeasurements from 'sentry/utils/useCustomMeasurements';
  7. import {DisplayType, WidgetType} from 'sentry/views/dashboards/types';
  8. import Visualize from 'sentry/views/dashboards/widgetBuilder/components/visualize';
  9. import {WidgetBuilderProvider} from 'sentry/views/dashboards/widgetBuilder/contexts/widgetBuilderContext';
  10. import {useSpanTags} from 'sentry/views/explore/contexts/spanTagsContext';
  11. jest.mock('sentry/utils/useCustomMeasurements');
  12. jest.mock('sentry/views/explore/contexts/spanTagsContext');
  13. describe('Visualize', () => {
  14. let organization;
  15. beforeEach(() => {
  16. organization = OrganizationFixture({
  17. features: ['dashboards-widget-builder-redesign', 'performance-view'],
  18. });
  19. jest.mocked(useCustomMeasurements).mockReturnValue({
  20. customMeasurements: {},
  21. });
  22. jest.mocked(useSpanTags).mockReturnValue({});
  23. });
  24. it('renders basic aggregates correctly from the URL params', async () => {
  25. render(
  26. <WidgetBuilderProvider>
  27. <Visualize />
  28. </WidgetBuilderProvider>,
  29. {
  30. organization,
  31. router: RouterFixture({
  32. location: LocationFixture({
  33. query: {
  34. yAxis: ['p90(transaction.duration)', 'max(spans.db)'],
  35. dataset: WidgetType.TRANSACTIONS,
  36. displayType: DisplayType.LINE,
  37. },
  38. }),
  39. }),
  40. }
  41. );
  42. expect(await screen.findByText('+ Add Series')).toBeInTheDocument();
  43. const p90FieldRow = (await screen.findByText('p90')).closest(
  44. '[data-testid="field-bar"]'
  45. ) as HTMLElement;
  46. expect(p90FieldRow).toBeInTheDocument();
  47. expect(within(p90FieldRow).getByText('transaction.duration')).toBeInTheDocument();
  48. const maxFieldRow = (await screen.findByText('max')).closest(
  49. '[data-testid="field-bar"]'
  50. ) as HTMLElement;
  51. expect(maxFieldRow).toBeInTheDocument();
  52. expect(within(maxFieldRow).getByText('spans.db')).toBeInTheDocument();
  53. });
  54. it('allows adding and deleting series', async () => {
  55. render(
  56. <WidgetBuilderProvider>
  57. <Visualize />
  58. </WidgetBuilderProvider>,
  59. {
  60. organization,
  61. router: RouterFixture({
  62. location: LocationFixture({
  63. query: {
  64. yAxis: ['max(spans.db)'],
  65. dataset: WidgetType.TRANSACTIONS,
  66. displayType: DisplayType.LINE,
  67. },
  68. }),
  69. }),
  70. }
  71. );
  72. expect(await screen.findByRole('button', {name: 'Remove field'})).toBeDisabled();
  73. await userEvent.click(screen.getByRole('button', {name: 'Add Series'}));
  74. expect(screen.queryAllByRole('button', {name: 'Remove field'})[0]).toBeEnabled();
  75. await userEvent.click(screen.queryAllByRole('button', {name: 'Remove field'})[0]);
  76. expect(screen.queryAllByRole('button', {name: 'Remove field'})[0]).toBeDisabled();
  77. });
  78. describe('spans', () => {
  79. beforeEach(() => {
  80. jest.mocked(useSpanTags).mockImplementation((type?: 'string' | 'number') => {
  81. if (type === 'number') {
  82. return {
  83. 'tags[span.duration,number]': {
  84. key: 'span.duration',
  85. name: 'span.duration',
  86. kind: 'measurement',
  87. },
  88. 'tags[anotherNumericTag,number]': {
  89. key: 'anotherNumericTag',
  90. name: 'anotherNumericTag',
  91. kind: 'measurement',
  92. },
  93. } as TagCollection;
  94. }
  95. return {
  96. 'span.description': {
  97. key: 'span.description',
  98. name: 'span.description',
  99. kind: 'tag',
  100. },
  101. } as TagCollection;
  102. });
  103. });
  104. it('shows numeric tags as primary options for chart widgets', async () => {
  105. render(
  106. <WidgetBuilderProvider>
  107. <Visualize />
  108. </WidgetBuilderProvider>,
  109. {
  110. organization,
  111. router: RouterFixture({
  112. location: LocationFixture({
  113. query: {
  114. dataset: WidgetType.SPANS,
  115. displayType: DisplayType.LINE,
  116. yAxis: ['p90(span.duration)'],
  117. },
  118. }),
  119. }),
  120. }
  121. );
  122. await userEvent.click(
  123. await screen.findByRole('button', {name: 'Column Selection'})
  124. );
  125. const listbox = await screen.findByRole('listbox', {name: 'Column Selection'});
  126. expect(within(listbox).getByText('anotherNumericTag')).toBeInTheDocument();
  127. expect(within(listbox).queryByText('span.description')).not.toBeInTheDocument();
  128. });
  129. it('shows the correct aggregate options', async () => {
  130. render(
  131. <WidgetBuilderProvider>
  132. <Visualize />
  133. </WidgetBuilderProvider>,
  134. {
  135. organization,
  136. router: RouterFixture({
  137. location: LocationFixture({
  138. query: {
  139. dataset: WidgetType.SPANS,
  140. displayType: DisplayType.LINE,
  141. yAxis: ['count(span.duration)'],
  142. },
  143. }),
  144. }),
  145. }
  146. );
  147. await userEvent.click(
  148. await screen.findByRole('button', {name: 'Aggregate Selection'})
  149. );
  150. // count has two entries because it's already selected
  151. // and in the dropdown
  152. expect(screen.getAllByText('count')).toHaveLength(2);
  153. expect(screen.getByText('avg')).toBeInTheDocument();
  154. expect(screen.getByText('max')).toBeInTheDocument();
  155. expect(screen.getByText('min')).toBeInTheDocument();
  156. expect(screen.getByText('p50')).toBeInTheDocument();
  157. expect(screen.getByText('p75')).toBeInTheDocument();
  158. expect(screen.getByText('p90')).toBeInTheDocument();
  159. expect(screen.getByText('p95')).toBeInTheDocument();
  160. expect(screen.getByText('p99')).toBeInTheDocument();
  161. expect(screen.getByText('p100')).toBeInTheDocument();
  162. expect(screen.getByText('sum')).toBeInTheDocument();
  163. });
  164. });
  165. });