actionDropdown.spec.tsx 6.4 KB

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