useTraceMeta.spec.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import {QueryClientProvider} from '@tanstack/react-query';
  2. import {OrganizationFixture} from 'sentry-fixture/organization';
  3. import {makeTestQueryClient} from 'sentry-test/queryClient';
  4. import {renderHook, waitFor} from 'sentry-test/reactTestingLibrary';
  5. import * as useOrganization from 'sentry/utils/useOrganization';
  6. import type {ReplayTrace} from 'sentry/views/replays/detail/trace/useReplayTraces';
  7. import {useTraceMeta} from './useTraceMeta';
  8. const organization = OrganizationFixture();
  9. const queryClient = makeTestQueryClient();
  10. const mockedReplayTraces: ReplayTrace[] = [
  11. {
  12. traceSlug: 'slug1',
  13. timestamp: 1,
  14. },
  15. {
  16. traceSlug: 'slug2',
  17. timestamp: 2,
  18. },
  19. {
  20. traceSlug: 'slug3',
  21. timestamp: 3,
  22. },
  23. ];
  24. describe('useTraceMeta', () => {
  25. beforeEach(function () {
  26. queryClient.clear();
  27. jest.clearAllMocks();
  28. jest.spyOn(useOrganization, 'default').mockReturnValue(organization);
  29. });
  30. it('Returns merged meta results', async () => {
  31. MockApiClient.addMockResponse({
  32. method: 'GET',
  33. url: '/organizations/org-slug/events-trace-meta/slug1/',
  34. body: {
  35. errors: 1,
  36. performance_issues: 1,
  37. projects: 1,
  38. transactions: 1,
  39. transaction_child_count_map: [{'transaction.id': '1', count: 1}],
  40. span_count: 1,
  41. span_count_map: {
  42. op1: 1,
  43. },
  44. },
  45. });
  46. MockApiClient.addMockResponse({
  47. method: 'GET',
  48. url: '/organizations/org-slug/events-trace-meta/slug2/',
  49. body: {
  50. errors: 1,
  51. performance_issues: 1,
  52. projects: 1,
  53. transactions: 1,
  54. transaction_child_count_map: [{'transaction.id': '2', count: 2}],
  55. span_count: 2,
  56. span_count_map: {
  57. op1: 1,
  58. op2: 1,
  59. },
  60. },
  61. });
  62. MockApiClient.addMockResponse({
  63. method: 'GET',
  64. url: '/organizations/org-slug/events-trace-meta/slug3/',
  65. body: {
  66. errors: 1,
  67. performance_issues: 1,
  68. projects: 1,
  69. transactions: 1,
  70. transaction_child_count_map: [],
  71. span_count: 1,
  72. span_count_map: {
  73. op3: 1,
  74. },
  75. },
  76. });
  77. const wrapper = ({children}: {children: React.ReactNode}) => (
  78. <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  79. );
  80. const {result} = renderHook(() => useTraceMeta(mockedReplayTraces), {wrapper});
  81. expect(result.current).toEqual({
  82. data: undefined,
  83. errors: [],
  84. status: 'pending',
  85. });
  86. await waitFor(() => expect(result.current.status === 'success').toBe(true));
  87. expect(result.current).toEqual({
  88. data: {
  89. errors: 3,
  90. performance_issues: 3,
  91. projects: 1,
  92. transactions: 3,
  93. transaction_child_count_map: {
  94. '1': 1,
  95. '2': 2,
  96. },
  97. span_count: 4,
  98. span_count_map: {
  99. op1: 2,
  100. op2: 1,
  101. op3: 1,
  102. },
  103. },
  104. errors: [],
  105. status: 'success',
  106. });
  107. });
  108. it('Collects errors from rejected api calls', async () => {
  109. const mockRequest1 = MockApiClient.addMockResponse({
  110. method: 'GET',
  111. url: '/organizations/org-slug/events-trace-meta/slug1/',
  112. statusCode: 400,
  113. });
  114. const mockRequest2 = MockApiClient.addMockResponse({
  115. method: 'GET',
  116. url: '/organizations/org-slug/events-trace-meta/slug2/',
  117. statusCode: 400,
  118. });
  119. const mockRequest3 = MockApiClient.addMockResponse({
  120. method: 'GET',
  121. url: '/organizations/org-slug/events-trace-meta/slug3/',
  122. statusCode: 400,
  123. });
  124. const wrapper = ({children}: {children: React.ReactNode}) => (
  125. <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  126. );
  127. const {result} = renderHook(() => useTraceMeta(mockedReplayTraces), {wrapper});
  128. expect(result.current).toEqual({
  129. data: undefined,
  130. errors: [],
  131. status: 'pending',
  132. });
  133. await waitFor(() => expect(result.current.status === 'pending').toBe(false));
  134. expect(result.current).toEqual({
  135. data: {
  136. errors: 0,
  137. performance_issues: 0,
  138. projects: 0,
  139. transactions: 0,
  140. transaction_child_count_map: {},
  141. span_count: 0,
  142. span_count_map: {},
  143. },
  144. errors: [expect.any(Error), expect.any(Error), expect.any(Error)],
  145. status: 'error',
  146. });
  147. expect(mockRequest1).toHaveBeenCalled();
  148. expect(mockRequest2).toHaveBeenCalled();
  149. expect(mockRequest3).toHaveBeenCalled();
  150. });
  151. it('Accumulates metaResults and collects errors from rejected api calls', async () => {
  152. const mockRequest1 = MockApiClient.addMockResponse({
  153. method: 'GET',
  154. url: '/organizations/org-slug/events-trace-meta/slug1/',
  155. statusCode: 400,
  156. });
  157. const mockRequest2 = MockApiClient.addMockResponse({
  158. method: 'GET',
  159. url: '/organizations/org-slug/events-trace-meta/slug2/',
  160. body: {
  161. errors: 1,
  162. performance_issues: 1,
  163. projects: 1,
  164. transactions: 1,
  165. transaction_child_count_map: [],
  166. span_count: 1,
  167. span_count_map: {
  168. op1: 1,
  169. },
  170. },
  171. });
  172. const mockRequest3 = MockApiClient.addMockResponse({
  173. method: 'GET',
  174. url: '/organizations/org-slug/events-trace-meta/slug3/',
  175. body: {
  176. errors: 1,
  177. performance_issues: 1,
  178. projects: 1,
  179. transactions: 1,
  180. transaction_child_count_map: [],
  181. span_count: 1,
  182. span_count_map: {
  183. op2: 1,
  184. },
  185. },
  186. });
  187. const wrapper = ({children}: {children: React.ReactNode}) => (
  188. <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  189. );
  190. const {result} = renderHook(() => useTraceMeta(mockedReplayTraces), {wrapper});
  191. expect(result.current).toEqual({
  192. data: undefined,
  193. errors: [],
  194. status: 'pending',
  195. });
  196. await waitFor(() => expect(result.current.status === 'pending').toBe(false));
  197. expect(result.current).toEqual({
  198. data: {
  199. errors: 2,
  200. performance_issues: 2,
  201. projects: 1,
  202. transactions: 2,
  203. transaction_child_count_map: {},
  204. span_count: 2,
  205. span_count_map: {
  206. op1: 1,
  207. op2: 1,
  208. },
  209. },
  210. errors: [expect.any(Error)],
  211. status: 'success',
  212. });
  213. expect(mockRequest1).toHaveBeenCalledTimes(1);
  214. expect(mockRequest2).toHaveBeenCalledTimes(1);
  215. expect(mockRequest3).toHaveBeenCalledTimes(1);
  216. });
  217. });