index.spec.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import {OrganizationFixture} from 'sentry-fixture/organization';
  2. import {ProjectFixture} from 'sentry-fixture/project';
  3. import {initializeOrg} from 'sentry-test/initializeOrg';
  4. import {generateSuspectSpansResponse} from 'sentry-test/performance/initializePerformanceData';
  5. import {act, render, screen, within} from 'sentry-test/reactTestingLibrary';
  6. import ProjectsStore from 'sentry/stores/projectsStore';
  7. import TransactionSpans from 'sentry/views/performance/transactionSummary/transactionSpans';
  8. import {
  9. SpanSortOthers,
  10. SpanSortPercentiles,
  11. } from 'sentry/views/performance/transactionSummary/transactionSpans/types';
  12. function initializeData({query} = {query: {}}) {
  13. const features = ['performance-view'];
  14. const organization = OrganizationFixture({
  15. features,
  16. projects: [ProjectFixture()],
  17. });
  18. const initialData = initializeOrg({
  19. organization,
  20. router: {
  21. location: {
  22. query: {
  23. transaction: 'Test Transaction',
  24. project: '1',
  25. ...query,
  26. },
  27. },
  28. },
  29. });
  30. act(() => void ProjectsStore.loadInitialData(initialData.organization.projects));
  31. return initialData;
  32. }
  33. describe('Performance > Transaction Spans', function () {
  34. let eventsMock;
  35. let eventsSpanOpsMock;
  36. let eventsSpansPerformanceMock;
  37. beforeEach(function () {
  38. MockApiClient.addMockResponse({
  39. url: '/organizations/org-slug/projects/',
  40. body: [],
  41. });
  42. MockApiClient.addMockResponse({
  43. url: '/organizations/org-slug/prompts-activity/',
  44. body: {},
  45. });
  46. MockApiClient.addMockResponse({
  47. url: '/organizations/org-slug/sdk-updates/',
  48. body: [],
  49. });
  50. MockApiClient.addMockResponse({
  51. url: '/organizations/org-slug/events-has-measurements/',
  52. body: {measurements: false},
  53. });
  54. eventsMock = MockApiClient.addMockResponse({
  55. url: '/organizations/org-slug/events/',
  56. body: [{'count()': 100}],
  57. });
  58. eventsSpanOpsMock = MockApiClient.addMockResponse({
  59. url: '/organizations/org-slug/events-span-ops/',
  60. body: [],
  61. });
  62. MockApiClient.addMockResponse({
  63. url: '/organizations/org-slug/replay-count/',
  64. body: {},
  65. });
  66. });
  67. afterEach(function () {
  68. MockApiClient.clearMockResponses();
  69. ProjectsStore.reset();
  70. });
  71. describe('Without Span Data', function () {
  72. beforeEach(function () {
  73. eventsSpansPerformanceMock = MockApiClient.addMockResponse({
  74. url: '/organizations/org-slug/events-spans-performance/',
  75. body: [],
  76. });
  77. });
  78. it('renders empty state', async function () {
  79. const initialData = initializeData({
  80. query: {sort: SpanSortOthers.SUM_EXCLUSIVE_TIME},
  81. });
  82. render(<TransactionSpans location={initialData.router.location} />, {
  83. context: initialData.routerContext,
  84. organization: initialData.organization,
  85. });
  86. expect(
  87. await screen.findByText('No results found for your query')
  88. ).toBeInTheDocument();
  89. });
  90. });
  91. describe('With Span Data', function () {
  92. beforeEach(function () {
  93. eventsSpansPerformanceMock = MockApiClient.addMockResponse({
  94. url: '/organizations/org-slug/events-spans-performance/',
  95. body: generateSuspectSpansResponse({examples: 0}),
  96. });
  97. });
  98. it('renders basic UI elements', async function () {
  99. const initialData = initializeData({
  100. query: {sort: SpanSortOthers.SUM_EXCLUSIVE_TIME},
  101. });
  102. render(<TransactionSpans location={initialData.router.location} />, {
  103. context: initialData.routerContext,
  104. organization: initialData.organization,
  105. });
  106. // default visible columns
  107. const grid = await screen.findByTestId('grid-editable');
  108. expect(await within(grid).findByText('Span Operation')).toBeInTheDocument();
  109. expect(await within(grid).findByText('Span Name')).toBeInTheDocument();
  110. expect(await within(grid).findByText('Frequency')).toBeInTheDocument();
  111. expect(await within(grid).findByText('P75 Self Time')).toBeInTheDocument();
  112. expect(await within(grid).findByText('Total Self Time')).toBeInTheDocument();
  113. // there should be a row for each of the spans
  114. expect(await within(grid).findByText('op1')).toBeInTheDocument();
  115. expect(await within(grid).findByText('op2')).toBeInTheDocument();
  116. expect(eventsMock).toHaveBeenCalledTimes(1);
  117. expect(eventsSpanOpsMock).toHaveBeenCalledTimes(1);
  118. expect(eventsSpansPerformanceMock).toHaveBeenCalledTimes(1);
  119. });
  120. [
  121. {sort: SpanSortPercentiles.P50_EXCLUSIVE_TIME, label: 'P50 Self Time'},
  122. {sort: SpanSortPercentiles.P75_EXCLUSIVE_TIME, label: 'P75 Self Time'},
  123. {sort: SpanSortPercentiles.P95_EXCLUSIVE_TIME, label: 'P95 Self Time'},
  124. {sort: SpanSortPercentiles.P99_EXCLUSIVE_TIME, label: 'P99 Self Time'},
  125. ].forEach(({sort, label}) => {
  126. it('renders the right percentile header', async function () {
  127. const initialData = initializeData({query: {sort}});
  128. render(<TransactionSpans location={initialData.router.location} />, {
  129. context: initialData.routerContext,
  130. organization: initialData.organization,
  131. });
  132. const grid = await screen.findByTestId('grid-editable');
  133. expect(await within(grid).findByText('Span Operation')).toBeInTheDocument();
  134. expect(await within(grid).findByText('Span Name')).toBeInTheDocument();
  135. expect(await within(grid).findByText('Frequency')).toBeInTheDocument();
  136. expect(await within(grid).findByText(label)).toBeInTheDocument();
  137. expect(await within(grid).findByText('Total Self Time')).toBeInTheDocument();
  138. });
  139. });
  140. it('renders the right avg occurrence header', async function () {
  141. const initialData = initializeData({query: {sort: SpanSortOthers.AVG_OCCURRENCE}});
  142. render(<TransactionSpans location={initialData.router.location} />, {
  143. context: initialData.routerContext,
  144. organization: initialData.organization,
  145. });
  146. const grid = await screen.findByTestId('grid-editable');
  147. expect(await within(grid).findByText('Span Operation')).toBeInTheDocument();
  148. expect(await within(grid).findByText('Span Name')).toBeInTheDocument();
  149. expect(await within(grid).findByText('Average Occurrences')).toBeInTheDocument();
  150. expect(await within(grid).findByText('Frequency')).toBeInTheDocument();
  151. expect(await within(grid).findByText('P75 Self Time')).toBeInTheDocument();
  152. expect(await within(grid).findByText('Total Self Time')).toBeInTheDocument();
  153. });
  154. });
  155. });