actionDropdown.spec.tsx 6.5 KB

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