actionDropdown.spec.tsx 6.4 KB

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