slowestFunctionsTable.spec.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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 ['slow-function', 'slow-package', '1.50s', '2.00s', '3.00s']) {
  73. expect(await screen.findByText(value)).toBeInTheDocument();
  74. }
  75. });
  76. it('paginates response', async () => {
  77. // @ts-expect-error partial schema mock
  78. const schema: Profiling.Schema = {
  79. metrics: [],
  80. };
  81. for (let i = 0; i < 10; i++) {
  82. schema.metrics?.push({
  83. name: 'slow-function',
  84. package: 'slow-package',
  85. p75: 1500 * 1e6,
  86. p95: 2000 * 1e6,
  87. p99: 3000 * 1e6,
  88. sum: 60_000 * 1e6,
  89. count: 5000,
  90. avg: 0.5 * 1e6,
  91. in_app: true,
  92. fingerprint: 12345,
  93. examples: [
  94. {
  95. project_id: 1,
  96. profile_id: 'profile-id',
  97. },
  98. ],
  99. });
  100. }
  101. MockApiClient.addMockResponse({
  102. url: '/organizations/org-slug/profiling/flamegraph/',
  103. match: [
  104. MockApiClient.matchQuery({
  105. expand: 'metrics',
  106. }),
  107. ],
  108. body: schema,
  109. });
  110. render(<SlowestFunctionsTable />);
  111. expect(await screen.findAllByText('slow-function')).toHaveLength(5);
  112. });
  113. it('paginates results', async () => {
  114. // @ts-expect-error partial schema mock
  115. const schema: Profiling.Schema = {
  116. metrics: [],
  117. };
  118. for (let i = 0; i < 10; i++) {
  119. schema.metrics?.push({
  120. name: 'slow-function-' + i,
  121. package: 'slow-package',
  122. p75: 1500 * 1e6,
  123. p95: 2000 * 1e6,
  124. p99: 3000 * 1e6,
  125. sum: 60_000 * 1e6,
  126. count: 5000,
  127. avg: 0.5 * 1e6,
  128. in_app: true,
  129. fingerprint: 12345,
  130. examples: [
  131. {
  132. project_id: 1,
  133. profile_id: 'profile-id',
  134. },
  135. ],
  136. });
  137. }
  138. MockApiClient.addMockResponse({
  139. url: '/organizations/org-slug/profiling/flamegraph/',
  140. match: [
  141. MockApiClient.matchQuery({
  142. expand: 'metrics',
  143. }),
  144. ],
  145. body: schema,
  146. });
  147. render(<SlowestFunctionsTable />);
  148. expect(await screen.findAllByText('slow-package')).toHaveLength(5);
  149. await userEvent.click(screen.getByLabelText('Next'));
  150. for (let i = 6; i < 10; i++) {
  151. expect(await screen.findByText('slow-function-' + i)).toBeInTheDocument();
  152. }
  153. expect(screen.getByLabelText('Next')).toBeDisabled();
  154. await userEvent.click(screen.getByLabelText('Previous'));
  155. for (let i = 0; i < 5; i++) {
  156. expect(await screen.findByText('slow-function-' + i)).toBeInTheDocument();
  157. }
  158. expect(screen.getByLabelText('Previous')).toBeDisabled();
  159. });
  160. it('fetches function metrics', async () => {
  161. // @ts-expect-error partial schema mock
  162. const schema: Profiling.Schema = {
  163. metrics: [],
  164. };
  165. for (let i = 0; i < 10; i++) {
  166. schema.metrics?.push({
  167. name: 'slow-function-' + i,
  168. package: 'slow-package',
  169. p75: 1500 * 1e6,
  170. p95: 2000 * 1e6,
  171. p99: 3000 * 1e6,
  172. sum: 60_000 * 1e6,
  173. count: 5000,
  174. avg: 0.5 * 1e6,
  175. in_app: true,
  176. fingerprint: 12345,
  177. examples: [
  178. {
  179. project_id: 1,
  180. profile_id: 'profile-id',
  181. },
  182. ],
  183. });
  184. }
  185. MockApiClient.addMockResponse({
  186. url: '/organizations/org-slug/profiling/flamegraph/',
  187. match: [
  188. MockApiClient.matchQuery({
  189. expand: 'metrics',
  190. }),
  191. ],
  192. body: schema,
  193. });
  194. const functionMetricsRequest = MockApiClient.addMockResponse({
  195. url: '/organizations/org-slug/events-stats/',
  196. match: [
  197. MockApiClient.matchQuery({
  198. query: 'fingerprint:12345',
  199. dataset: 'profileFunctionsMetrics',
  200. }),
  201. ],
  202. body: [],
  203. });
  204. render(<SlowestFunctionsTable />);
  205. const expandButtons = await screen.findAllByLabelText('View Function Metrics');
  206. expect(expandButtons).toHaveLength(5);
  207. await userEvent.click(expandButtons[0]);
  208. await waitFor(() => {
  209. expect(functionMetricsRequest).toHaveBeenCalled();
  210. });
  211. });
  212. });