actionDropdown.spec.tsx 6.3 KB

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