pageOverview.spec.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import {OrganizationFixture} from 'sentry-fixture/organization';
  2. import {render, waitFor} from 'sentry-test/reactTestingLibrary';
  3. import {useLocation} from 'sentry/utils/useLocation';
  4. import usePageFilters from 'sentry/utils/usePageFilters';
  5. import PageOverview from 'sentry/views/performance/browser/webVitals/pageOverview';
  6. jest.mock('sentry/utils/useLocation');
  7. jest.mock('sentry/utils/usePageFilters');
  8. describe('PageOverview', function () {
  9. const organization = OrganizationFixture({
  10. features: ['insights-initial-modules'],
  11. });
  12. let eventsMock;
  13. beforeEach(function () {
  14. jest.mocked(useLocation).mockReturnValue({
  15. pathname: '',
  16. search: '',
  17. query: {},
  18. hash: '',
  19. state: undefined,
  20. action: 'PUSH',
  21. key: '',
  22. });
  23. jest.mocked(usePageFilters).mockReturnValue({
  24. isReady: true,
  25. desyncedFilters: new Set(),
  26. pinnedFilters: new Set(),
  27. shouldPersist: true,
  28. selection: {
  29. datetime: {
  30. period: '10d',
  31. start: null,
  32. end: null,
  33. utc: false,
  34. },
  35. environments: [],
  36. projects: [],
  37. },
  38. });
  39. eventsMock = MockApiClient.addMockResponse({
  40. url: `/organizations/${organization.slug}/events/`,
  41. body: {
  42. data: [],
  43. },
  44. });
  45. MockApiClient.addMockResponse({
  46. url: `/organizations/${organization.slug}/events-stats/`,
  47. body: {},
  48. });
  49. MockApiClient.addMockResponse({
  50. url: `/organizations/${organization.slug}/spans-aggregation/`,
  51. body: {},
  52. });
  53. });
  54. afterEach(function () {
  55. jest.clearAllMocks();
  56. });
  57. it('renders', () => {
  58. render(<PageOverview />, {organization});
  59. // Raw web vital metric tile queries
  60. expect(eventsMock).toHaveBeenNthCalledWith(
  61. 1,
  62. expect.anything(),
  63. expect.objectContaining({
  64. query: expect.objectContaining({
  65. dataset: 'metrics',
  66. field: [
  67. 'p75(measurements.lcp)',
  68. 'p75(measurements.fcp)',
  69. 'p75(measurements.cls)',
  70. 'p75(measurements.ttfb)',
  71. 'p75(measurements.fid)',
  72. 'p75(measurements.inp)',
  73. 'p75(transaction.duration)',
  74. 'count_web_vitals(measurements.lcp, any)',
  75. 'count_web_vitals(measurements.fcp, any)',
  76. 'count_web_vitals(measurements.cls, any)',
  77. 'count_web_vitals(measurements.fid, any)',
  78. 'count_web_vitals(measurements.ttfb, any)',
  79. 'count()',
  80. ],
  81. query:
  82. 'transaction.op:[pageload,""] span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,""] !transaction:"<< unparameterized >>"',
  83. }),
  84. })
  85. );
  86. // Project performance score ring query
  87. expect(eventsMock).toHaveBeenNthCalledWith(
  88. 2,
  89. expect.anything(),
  90. expect.objectContaining({
  91. query: expect.objectContaining({
  92. dataset: 'metrics',
  93. field: [
  94. 'performance_score(measurements.score.lcp)',
  95. 'performance_score(measurements.score.fcp)',
  96. 'performance_score(measurements.score.cls)',
  97. `performance_score(measurements.score.inp)`,
  98. 'performance_score(measurements.score.ttfb)',
  99. 'avg(measurements.score.total)',
  100. 'avg(measurements.score.weight.lcp)',
  101. 'avg(measurements.score.weight.fcp)',
  102. 'avg(measurements.score.weight.cls)',
  103. `avg(measurements.score.weight.inp)`,
  104. 'avg(measurements.score.weight.ttfb)',
  105. 'count()',
  106. 'count_scores(measurements.score.total)',
  107. 'count_scores(measurements.score.lcp)',
  108. 'count_scores(measurements.score.fcp)',
  109. 'count_scores(measurements.score.cls)',
  110. 'count_scores(measurements.score.ttfb)',
  111. `count_scores(measurements.score.inp)`,
  112. ],
  113. query:
  114. 'transaction.op:[pageload,""] span.op:[ui.interaction.click,ui.interaction.hover,ui.interaction.drag,ui.interaction.press,""] !transaction:"<< unparameterized >>"',
  115. }),
  116. })
  117. );
  118. });
  119. it('renders interaction samples', async () => {
  120. const organizationWithInp = OrganizationFixture({
  121. features: ['insights-initial-modules'],
  122. });
  123. jest.mocked(useLocation).mockReturnValue({
  124. pathname: '',
  125. search: '',
  126. query: {useStoredScores: 'true', transaction: '/', type: 'interactions'},
  127. hash: '',
  128. state: undefined,
  129. action: 'PUSH',
  130. key: '',
  131. });
  132. render(<PageOverview />, {organization: organizationWithInp});
  133. await waitFor(() =>
  134. expect(eventsMock).toHaveBeenCalledWith(
  135. '/organizations/org-slug/events/',
  136. expect.objectContaining({
  137. query: expect.objectContaining({
  138. dataset: 'spansIndexed',
  139. field: [
  140. 'measurements.inp',
  141. 'measurements.score.inp',
  142. 'measurements.score.weight.inp',
  143. 'measurements.score.total',
  144. 'span_id',
  145. 'timestamp',
  146. 'profile_id',
  147. 'replay.id',
  148. 'user',
  149. 'origin.transaction',
  150. 'project',
  151. 'browser.name',
  152. 'span.self_time',
  153. 'span.description',
  154. ],
  155. query:
  156. 'has:message !span.description:<unknown> span.op:ui.interaction.click measurements.score.weight.inp:>0 origin.transaction:/',
  157. }),
  158. })
  159. )
  160. );
  161. });
  162. it('escapes transaction name before querying discover', async () => {
  163. const organizationWithInp = OrganizationFixture({
  164. features: ['insights-initial-modules'],
  165. });
  166. jest.mocked(useLocation).mockReturnValue({
  167. pathname: '',
  168. search: '',
  169. query: {
  170. useStoredScores: 'true',
  171. transaction: '/page-with-a-*/',
  172. type: 'interactions',
  173. },
  174. hash: '',
  175. state: undefined,
  176. action: 'PUSH',
  177. key: '',
  178. });
  179. render(<PageOverview />, {organization: organizationWithInp});
  180. await waitFor(() =>
  181. expect(eventsMock).toHaveBeenCalledWith(
  182. '/organizations/org-slug/events/',
  183. expect.objectContaining({
  184. query: expect.objectContaining({
  185. dataset: 'spansIndexed',
  186. field: [
  187. 'measurements.inp',
  188. 'measurements.score.inp',
  189. 'measurements.score.weight.inp',
  190. 'measurements.score.total',
  191. 'span_id',
  192. 'timestamp',
  193. 'profile_id',
  194. 'replay.id',
  195. 'user',
  196. 'origin.transaction',
  197. 'project',
  198. 'browser.name',
  199. 'span.self_time',
  200. 'span.description',
  201. ],
  202. query:
  203. 'has:message !span.description:<unknown> span.op:ui.interaction.click measurements.score.weight.inp:>0 origin.transaction:"/page-with-a-\\*/"',
  204. }),
  205. })
  206. )
  207. );
  208. });
  209. });