index.spec.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import {LocationFixture} from 'sentry-fixture/locationFixture';
  2. import type {InitializeDataSettings} from 'sentry-test/performance/initializePerformanceData';
  3. import {initializeData as _initializeData} from 'sentry-test/performance/initializePerformanceData';
  4. import {act, render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  5. import ProjectsStore from 'sentry/stores/projectsStore';
  6. import {MEPSettingProvider} from 'sentry/utils/performance/contexts/metricsEnhancedSetting';
  7. import {useLocation} from 'sentry/utils/useLocation';
  8. import TransactionEvents from 'sentry/views/performance/transactionSummary/transactionEvents';
  9. import {
  10. EVENTS_TABLE_RESPONSE_FIELDS,
  11. MOCK_EVENTS_TABLE_DATA,
  12. } from 'sentry/views/performance/transactionSummary/transactionEvents/testUtils';
  13. jest.mock('sentry/utils/useLocation');
  14. const mockUseLocation = jest.mocked(useLocation);
  15. function WrappedComponent({data}: {data: ReturnType<typeof initializeData>}) {
  16. return (
  17. <MEPSettingProvider>
  18. <TransactionEvents
  19. organization={data.organization}
  20. location={data.router.location}
  21. />
  22. </MEPSettingProvider>
  23. );
  24. }
  25. const setupMockApiResponeses = () => {
  26. MockApiClient.addMockResponse({
  27. url: '/organizations/org-slug/events-has-measurements/',
  28. body: {measurements: false},
  29. });
  30. MockApiClient.addMockResponse({
  31. url: '/organizations/org-slug/events/',
  32. body: {
  33. data: [
  34. {
  35. 'p100()': 9500,
  36. 'p99()': 9000,
  37. 'p95()': 7000,
  38. 'p75()': 5000,
  39. 'p50()': 500,
  40. },
  41. ],
  42. meta: {
  43. fields: {
  44. 'p100()': 'duration',
  45. 'p99()': 'duration',
  46. 'p95()': 'duration',
  47. 'p75()': 'duration',
  48. 'p50()': 'duration',
  49. },
  50. },
  51. },
  52. match: [
  53. (_, options) => {
  54. return options.query?.field?.includes('p95()');
  55. },
  56. ],
  57. });
  58. MockApiClient.addMockResponse({
  59. url: '/organizations/org-slug/events/',
  60. body: {
  61. data: [
  62. {
  63. 'count()': 4000,
  64. },
  65. ],
  66. meta: {
  67. fields: {
  68. 'count()': 'integer',
  69. },
  70. },
  71. },
  72. match: [
  73. (_, options) => {
  74. return options.query?.field?.includes('count()');
  75. },
  76. ],
  77. });
  78. MockApiClient.addMockResponse({
  79. url: '/organizations/org-slug/events/',
  80. body: {
  81. data: [
  82. {
  83. 'count()': 4000,
  84. },
  85. ],
  86. meta: {
  87. fields: {
  88. 'count()': 'integer',
  89. },
  90. },
  91. },
  92. match: [(_, options) => options.query?.field?.includes('count()')],
  93. });
  94. MockApiClient.addMockResponse({
  95. url: '/organizations/org-slug/events/',
  96. body: {
  97. data: MOCK_EVENTS_TABLE_DATA,
  98. meta: {
  99. fields: EVENTS_TABLE_RESPONSE_FIELDS,
  100. },
  101. },
  102. match: [
  103. (_, options) =>
  104. options.query?.field?.includes('transaction.duration') &&
  105. !options.query?.query.includes('transaction.duration'),
  106. ],
  107. });
  108. MockApiClient.addMockResponse({
  109. url: '/organizations/org-slug/events/',
  110. body: {
  111. data: [MOCK_EVENTS_TABLE_DATA[0]],
  112. meta: {
  113. fields: EVENTS_TABLE_RESPONSE_FIELDS,
  114. },
  115. },
  116. match: [
  117. (_, options) =>
  118. options.query?.field?.includes('transaction.duration') &&
  119. options.query?.query.includes('transaction.duration:<=500'), // 500 refers to p50 value
  120. ],
  121. });
  122. MockApiClient.addMockResponse({
  123. url: '/organizations/org-slug/replay-count/',
  124. body: {},
  125. });
  126. MockApiClient.addMockResponse({
  127. url: `/organizations/org-slug/recent-searches/`,
  128. body: [],
  129. });
  130. MockApiClient.addMockResponse({
  131. url: `/organizations/org-slug/tags/`,
  132. body: [],
  133. });
  134. };
  135. const setupMocks = () => {
  136. mockUseLocation.mockReturnValue(
  137. LocationFixture({pathname: '/organizations/org-slug/performance/summary'})
  138. );
  139. };
  140. const initializeData = (settings?: InitializeDataSettings) => {
  141. settings = {
  142. features: ['performance-view'],
  143. query: {project: '1', transaction: 'transaction'},
  144. ...settings,
  145. };
  146. const data = _initializeData(settings);
  147. act(() => void ProjectsStore.loadInitialData(data.projects));
  148. return data;
  149. };
  150. describe('Performance > Transaction Summary > Transaction Events > Index', () => {
  151. beforeEach(() => {
  152. setupMockApiResponeses();
  153. setupMocks();
  154. });
  155. afterEach(() => {
  156. MockApiClient.clearMockResponses();
  157. jest.clearAllMocks();
  158. });
  159. it('should contain all transaction events', async () => {
  160. const data = initializeData();
  161. render(<WrappedComponent data={data} />, {router: data.router});
  162. expect(await screen.findByText('uhoh@example.com')).toBeInTheDocument();
  163. expect(await screen.findByText('moreuhoh@example.com')).toBeInTheDocument();
  164. });
  165. it('should filter the transaction duration if in query', async () => {
  166. const data = initializeData({
  167. query: {project: '1', transaction: 'transaction', showTransactions: 'p50'},
  168. });
  169. render(<WrappedComponent data={data} />, {router: data.router});
  170. expect(await screen.findByText('uhoh@example.com')).toBeInTheDocument();
  171. expect(screen.queryByText('moreuhoh@example.com')).not.toBeInTheDocument();
  172. });
  173. it('should update transaction percentile query if selected', async () => {
  174. const data = initializeData();
  175. render(<WrappedComponent data={data} />, {router: data.router});
  176. const percentileButton = await screen.findByRole('button', {
  177. name: /percentile p100/i,
  178. });
  179. await userEvent.click(percentileButton);
  180. const p50 = screen.getByRole('option', {name: 'p50'});
  181. expect(p50).toBeInTheDocument();
  182. await userEvent.click(p50);
  183. expect(data.router.push).toHaveBeenCalledWith(
  184. expect.objectContaining({query: expect.objectContaining({showTransactions: 'p50'})})
  185. );
  186. });
  187. });