slowestFunctionsTable.spec.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  2. import {SlowestFunctionsTable} from 'sentry/views/profiling/landing/slowestFunctionsTable';
  3. describe('SlowestFunctionsTable', () => {
  4. it('shows loading state', () => {
  5. MockApiClient.addMockResponse({
  6. url: '/organizations/org-slug/profiling/flamegraph/',
  7. body: [],
  8. });
  9. render(<SlowestFunctionsTable />);
  10. expect(screen.getByTestId('loading-indicator')).toBeInTheDocument();
  11. });
  12. it('shows error state', async () => {
  13. MockApiClient.addMockResponse({
  14. url: '/organizations/org-slug/profiling/flamegraph/',
  15. body: [],
  16. statusCode: 500,
  17. });
  18. render(<SlowestFunctionsTable />);
  19. expect(await screen.findByTestId('error-indicator')).toBeInTheDocument();
  20. });
  21. it('shows no functions state', async () => {
  22. // @ts-expect-error partial schema mock
  23. const schema: Profiling.Schema = {
  24. metrics: [],
  25. };
  26. MockApiClient.addMockResponse({
  27. url: '/organizations/org-slug/profiling/flamegraph/',
  28. match: [
  29. MockApiClient.matchQuery({
  30. expand: 'metrics',
  31. }),
  32. ],
  33. body: schema,
  34. });
  35. render(<SlowestFunctionsTable />);
  36. expect(await screen.findByText('No functions found')).toBeInTheDocument();
  37. });
  38. it('renders function fields', async () => {
  39. // @ts-expect-error partial schema mock
  40. const schema: Profiling.Schema = {
  41. metrics: [
  42. {
  43. name: 'slow-function',
  44. package: 'slow-package',
  45. p75: 1500 * 1e6,
  46. p95: 2000 * 1e6,
  47. p99: 3000 * 1e6,
  48. sum: 60_000 * 1e6,
  49. count: 5000,
  50. avg: 0.5 * 1e6,
  51. in_app: true,
  52. fingerprint: 12345,
  53. examples: [
  54. {
  55. project_id: 1,
  56. profile_id: 'profile-id',
  57. },
  58. ],
  59. },
  60. ],
  61. };
  62. MockApiClient.addMockResponse({
  63. url: '/organizations/org-slug/profiling/flamegraph/',
  64. match: [
  65. MockApiClient.matchQuery({
  66. expand: 'metrics',
  67. }),
  68. ],
  69. body: schema,
  70. });
  71. render(<SlowestFunctionsTable />);
  72. for (const value of [
  73. 'slow-function',
  74. 'slow-package',
  75. '5k',
  76. '1.50s',
  77. '2.00s',
  78. '3.00s',
  79. '1.00min',
  80. ]) {
  81. expect(await screen.findByText(value)).toBeInTheDocument();
  82. }
  83. });
  84. it('paginates response', async () => {
  85. // @ts-expect-error partial schema mock
  86. const schema: Profiling.Schema = {
  87. metrics: [],
  88. };
  89. for (let i = 0; i < 10; i++) {
  90. schema.metrics?.push({
  91. name: 'slow-function',
  92. package: 'slow-package',
  93. p75: 1500 * 1e6,
  94. p95: 2000 * 1e6,
  95. p99: 3000 * 1e6,
  96. sum: 60_000 * 1e6,
  97. count: 5000,
  98. avg: 0.5 * 1e6,
  99. in_app: true,
  100. fingerprint: 12345,
  101. examples: [
  102. {
  103. project_id: 1,
  104. profile_id: 'profile-id',
  105. },
  106. ],
  107. });
  108. }
  109. MockApiClient.addMockResponse({
  110. url: '/organizations/org-slug/profiling/flamegraph/',
  111. match: [
  112. MockApiClient.matchQuery({
  113. expand: 'metrics',
  114. }),
  115. ],
  116. body: schema,
  117. });
  118. render(<SlowestFunctionsTable />);
  119. expect(await screen.findAllByText('slow-function')).toHaveLength(5);
  120. });
  121. it('paginates results', async () => {
  122. // @ts-expect-error partial schema mock
  123. const schema: Profiling.Schema = {
  124. metrics: [],
  125. };
  126. for (let i = 0; i < 10; i++) {
  127. schema.metrics?.push({
  128. name: 'slow-function-' + i,
  129. package: 'slow-package',
  130. p75: 1500 * 1e6,
  131. p95: 2000 * 1e6,
  132. p99: 3000 * 1e6,
  133. sum: 60_000 * 1e6,
  134. count: 5000,
  135. avg: 0.5 * 1e6,
  136. in_app: true,
  137. fingerprint: 12345,
  138. examples: [
  139. {
  140. project_id: 1,
  141. profile_id: 'profile-id',
  142. },
  143. ],
  144. });
  145. }
  146. MockApiClient.addMockResponse({
  147. url: '/organizations/org-slug/profiling/flamegraph/',
  148. match: [
  149. MockApiClient.matchQuery({
  150. expand: 'metrics',
  151. }),
  152. ],
  153. body: schema,
  154. });
  155. render(<SlowestFunctionsTable />);
  156. expect(await screen.findAllByText('slow-package')).toHaveLength(5);
  157. userEvent.click(screen.getByLabelText('Next'));
  158. for (let i = 6; i < 10; i++) {
  159. expect(await screen.findByText('slow-function-' + i)).toBeInTheDocument();
  160. }
  161. expect(screen.getByLabelText('Next')).toBeDisabled();
  162. userEvent.click(screen.getByLabelText('Previous'));
  163. for (let i = 0; i < 5; i++) {
  164. expect(await screen.findByText('slow-function-' + i)).toBeInTheDocument();
  165. }
  166. expect(screen.getByLabelText('Previous')).toBeDisabled();
  167. });
  168. it('fetches function metrics', async () => {
  169. // @ts-expect-error partial schema mock
  170. const schema: Profiling.Schema = {
  171. metrics: [],
  172. };
  173. for (let i = 0; i < 10; i++) {
  174. schema.metrics?.push({
  175. name: 'slow-function-' + i,
  176. package: 'slow-package',
  177. p75: 1500 * 1e6,
  178. p95: 2000 * 1e6,
  179. p99: 3000 * 1e6,
  180. sum: 60_000 * 1e6,
  181. count: 5000,
  182. avg: 0.5 * 1e6,
  183. in_app: true,
  184. fingerprint: 12345,
  185. examples: [
  186. {
  187. project_id: 1,
  188. profile_id: 'profile-id',
  189. },
  190. ],
  191. });
  192. }
  193. MockApiClient.addMockResponse({
  194. url: '/organizations/org-slug/profiling/flamegraph/',
  195. match: [
  196. MockApiClient.matchQuery({
  197. expand: 'metrics',
  198. }),
  199. ],
  200. body: schema,
  201. });
  202. const functionMetricsRequest = MockApiClient.addMockResponse({
  203. url: '/organizations/org-slug/events-stats/',
  204. match: [
  205. MockApiClient.matchQuery({
  206. query: 'fingerprint:12345',
  207. dataset: 'profileFunctionsMetrics',
  208. }),
  209. ],
  210. body: [],
  211. });
  212. render(<SlowestFunctionsTable />);
  213. const expandButtons = await screen.findAllByLabelText('View Function Metrics');
  214. expect(expandButtons).toHaveLength(5);
  215. await userEvent.click(expandButtons[0]);
  216. await waitFor(() => {
  217. expect(functionMetricsRequest).toHaveBeenCalled();
  218. });
  219. });
  220. });