actionDropdown.spec.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import type {Location} from 'history';
  2. import {LocationFixture} from 'sentry-fixture/locationFixture';
  3. import {OrganizationFixture} from 'sentry-fixture/organization';
  4. import {RouterFixture} from 'sentry-fixture/routerFixture';
  5. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  6. import type {EventData} from 'sentry/utils/discover/eventView';
  7. import EventView from 'sentry/utils/discover/eventView';
  8. import ActionDropDown, {ContextValueType} from './actionDropdown';
  9. const dataRow: EventData = {
  10. id: '6b43e285de834ec5b5fe30d62d549b20',
  11. issue: 'SENTRY-VVY',
  12. release: 'backend@22.10.0+aaf33944f93dc8fa4234ca046a8d88fb1dccfb76',
  13. 'issue.id': 3512441874,
  14. 'project.name': 'sentry',
  15. };
  16. const mockEventView = EventView.fromSavedQuery({
  17. id: '',
  18. name: 'test query',
  19. version: 2,
  20. fields: ['title', 'issue'],
  21. query: 'event.type:error',
  22. projects: [1],
  23. });
  24. const mockedLocation = LocationFixture({
  25. query: {
  26. field: 'title',
  27. },
  28. });
  29. const mockedRouter = RouterFixture();
  30. const renderActionDropdown = (
  31. location: Location,
  32. eventView: EventView,
  33. queryKey: string,
  34. value: React.ReactText | string[],
  35. contextValueType: ContextValueType
  36. ) => {
  37. const organization = OrganizationFixture();
  38. render(
  39. <ActionDropDown
  40. dataRow={dataRow}
  41. organization={organization}
  42. location={location}
  43. eventView={eventView}
  44. queryKey={queryKey}
  45. value={value}
  46. contextValueType={contextValueType}
  47. />,
  48. {organization, router: mockedRouter}
  49. );
  50. };
  51. describe('Quick Context Actions', function () {
  52. afterEach(() => {
  53. MockApiClient.clearMockResponses();
  54. });
  55. it('Renders correct options for string context value', async () => {
  56. renderActionDropdown(
  57. mockedLocation,
  58. mockEventView,
  59. 'title',
  60. 'Undefined: Error',
  61. ContextValueType.STRING
  62. );
  63. const trigger = await screen.findByTestId('quick-context-action-trigger');
  64. expect(trigger).toBeInTheDocument();
  65. await userEvent.click(trigger);
  66. const menuOptions = await screen.findAllByRole('menuitemradio');
  67. expect(menuOptions.map(e => e.textContent)).toEqual([
  68. 'Add as column',
  69. 'Add to filter',
  70. 'Exclude from filter',
  71. ]);
  72. });
  73. it('Renders correct options for non-string context value', async () => {
  74. renderActionDropdown(
  75. mockedLocation,
  76. mockEventView,
  77. 'transaction.duration',
  78. '14.00ms',
  79. ContextValueType.DURATION
  80. );
  81. const trigger = await screen.findByTestId('quick-context-action-trigger');
  82. expect(trigger).toBeInTheDocument();
  83. await userEvent.click(trigger);
  84. const menuOptions = await screen.findAllByRole('menuitemradio');
  85. expect(menuOptions.map(e => e.textContent)).toEqual([
  86. 'Add as column',
  87. 'Show values greater than',
  88. 'Show values less than',
  89. ]);
  90. });
  91. it('Adds context as column', async () => {
  92. renderActionDropdown(
  93. mockedLocation,
  94. mockEventView,
  95. 'transaction.duration',
  96. '14.00ms',
  97. ContextValueType.DURATION
  98. );
  99. const trigger = await screen.findByTestId('quick-context-action-trigger');
  100. expect(trigger).toBeInTheDocument();
  101. await userEvent.click(trigger);
  102. const addAsColumn = await screen.findByRole('menuitemradio', {name: 'Add as column'});
  103. await userEvent.click(addAsColumn);
  104. expect(mockedRouter.push).toHaveBeenCalledWith(
  105. expect.objectContaining({
  106. pathname: '/mock-pathname/',
  107. query: expect.objectContaining({
  108. field: ['title', 'issue', 'transaction.duration'],
  109. }),
  110. })
  111. );
  112. });
  113. it('Adds context to filter', async () => {
  114. renderActionDropdown(
  115. mockedLocation,
  116. mockEventView,
  117. 'title',
  118. 'Undefined: Error',
  119. ContextValueType.STRING
  120. );
  121. const trigger = await screen.findByTestId('quick-context-action-trigger');
  122. expect(trigger).toBeInTheDocument();
  123. await userEvent.click(trigger);
  124. const addToFilter = await screen.findByRole('menuitemradio', {name: 'Add to filter'});
  125. await userEvent.click(addToFilter);
  126. expect(mockedRouter.push).toHaveBeenCalledWith(
  127. expect.objectContaining({
  128. pathname: '/mock-pathname/',
  129. query: expect.objectContaining({
  130. query: 'event.type:error title:"Undefined: Error"',
  131. }),
  132. })
  133. );
  134. });
  135. it('Excludes context from filter', async () => {
  136. renderActionDropdown(
  137. mockedLocation,
  138. mockEventView,
  139. 'title',
  140. 'Undefined: Error',
  141. ContextValueType.STRING
  142. );
  143. const trigger = await screen.findByTestId('quick-context-action-trigger');
  144. expect(trigger).toBeInTheDocument();
  145. await userEvent.click(trigger);
  146. const addToFilter = await screen.findByRole('menuitemradio', {
  147. name: 'Exclude from filter',
  148. });
  149. await userEvent.click(addToFilter);
  150. expect(mockedRouter.push).toHaveBeenCalledWith(
  151. expect.objectContaining({
  152. pathname: '/mock-pathname/',
  153. query: expect.objectContaining({
  154. query: 'event.type:error !title:"Undefined: Error"',
  155. }),
  156. })
  157. );
  158. });
  159. it('Filters by values greater than', async () => {
  160. renderActionDropdown(
  161. mockedLocation,
  162. mockEventView,
  163. 'transaction.duration',
  164. '14.00ms',
  165. ContextValueType.DURATION
  166. );
  167. const trigger = await screen.findByTestId('quick-context-action-trigger');
  168. expect(trigger).toBeInTheDocument();
  169. await userEvent.click(trigger);
  170. const showGreaterThanBtn = await screen.findByRole('menuitemradio', {
  171. name: 'Show values greater than',
  172. });
  173. await userEvent.click(showGreaterThanBtn);
  174. expect(mockedRouter.push).toHaveBeenCalledWith(
  175. expect.objectContaining({
  176. pathname: '/mock-pathname/',
  177. query: expect.objectContaining({
  178. query: 'event.type:error transaction.duration:>14.00ms',
  179. }),
  180. })
  181. );
  182. });
  183. it('Filters by values less than', async () => {
  184. renderActionDropdown(
  185. mockedLocation,
  186. mockEventView,
  187. 'transaction.duration',
  188. '14.00ms',
  189. ContextValueType.DURATION
  190. );
  191. const trigger = await screen.findByTestId('quick-context-action-trigger');
  192. expect(trigger).toBeInTheDocument();
  193. await userEvent.click(trigger);
  194. const showLessThanBtn = await screen.findByRole('menuitemradio', {
  195. name: 'Show values less than',
  196. });
  197. await userEvent.click(showLessThanBtn);
  198. expect(mockedRouter.push).toHaveBeenCalledWith(
  199. expect.objectContaining({
  200. pathname: '/mock-pathname/',
  201. query: expect.objectContaining({
  202. query: 'event.type:error transaction.duration:<14.00ms',
  203. }),
  204. })
  205. );
  206. });
  207. });