metricsBaselineContainer.spec.tsx 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import ReactEchartsCore from 'echarts-for-react/lib/core';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {addMetricsDataMock} from 'sentry-test/performance/addMetricsDataMock';
  4. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  5. import {Organization} from 'sentry/types/organization';
  6. import {Project} from 'sentry/types/project';
  7. import EventView from 'sentry/utils/discover/eventView';
  8. import {MetricsCardinalityProvider} from 'sentry/utils/performance/contexts/metricsCardinality';
  9. import {MetricsBaselineContainer} from './metricsBaselineContainer';
  10. jest.mock('echarts-for-react/lib/core', () => {
  11. return jest.fn(({style}) => {
  12. return <div style={{...style, background: 'green'}}>echarts mock</div>;
  13. });
  14. });
  15. export function renderMetricsBaselineContainer(
  16. organization: Organization,
  17. project: Project,
  18. eventView: EventView,
  19. yAxis: string[]
  20. ) {
  21. const routerLocation: {query: {project?: number}} = {
  22. query: {project: parseInt(project.id, 10)},
  23. };
  24. const router = {
  25. location: routerLocation,
  26. };
  27. const initialData = initializeOrg({
  28. organization,
  29. projects: [project],
  30. project,
  31. router,
  32. });
  33. const location = initialData.router.location;
  34. const api = new MockApiClient();
  35. render(
  36. <MetricsCardinalityProvider location={location} organization={organization}>
  37. <MetricsBaselineContainer
  38. organization={organization}
  39. total={100}
  40. onAxisChange={() => undefined}
  41. onDisplayChange={() => undefined}
  42. onTopEventsChange={() => undefined}
  43. onIntervalChange={() => undefined}
  44. eventView={eventView}
  45. api={api}
  46. confirmedQuery
  47. location={location}
  48. router={initialData.router}
  49. yAxis={yAxis}
  50. />
  51. </MetricsCardinalityProvider>
  52. );
  53. return initialData.router;
  54. }
  55. describe('MetricsBaselineContainer', function () {
  56. const features = ['discover-basic'];
  57. const project = TestStubs.Project();
  58. const eventView = EventView.fromSavedQuery({
  59. id: '',
  60. name: 'test query',
  61. version: 2,
  62. fields: ['transaction', 'p50(transaction.duration)'],
  63. projects: [project.id],
  64. });
  65. let eventsStatsMock: jest.Mock | undefined;
  66. let eventsMock: jest.Mock | undefined;
  67. beforeEach(function () {
  68. (ReactEchartsCore as jest.Mock).mockClear();
  69. eventsStatsMock = MockApiClient.addMockResponse({
  70. url: '/organizations/org-slug/events-stats/',
  71. body: {
  72. data: [
  73. [1663272000, [{count: 2066}]],
  74. [1663272300, [{count: 2158}]],
  75. ],
  76. },
  77. });
  78. eventsMock = MockApiClient.addMockResponse({
  79. method: 'GET',
  80. url: `/organizations/org-slug/events/`,
  81. body: {
  82. data: [{}],
  83. meta: {},
  84. },
  85. });
  86. MockApiClient.addMockResponse({
  87. url: '/organizations/org-slug/releases/stats/',
  88. body: [],
  89. });
  90. });
  91. afterEach(() => {
  92. jest.clearAllMocks();
  93. });
  94. it('enables processed baseline toggle if metrics cardinality conditions met', async function () {
  95. addMetricsDataMock();
  96. eventsMock = MockApiClient.addMockResponse({
  97. method: 'GET',
  98. url: `/organizations/org-slug/events/`,
  99. body: {
  100. data: [{'count()': 19266771}],
  101. meta: {},
  102. },
  103. });
  104. const organization = TestStubs.Organization({
  105. features: [
  106. ...features,
  107. 'discover-metrics-baseline',
  108. 'server-side-sampling',
  109. 'mep-rollout-flag',
  110. ],
  111. });
  112. const yAxis = ['p50(transaction.duration)'];
  113. renderMetricsBaselineContainer(organization, project, eventView, yAxis);
  114. await waitFor(() => {
  115. expect(eventsStatsMock).toHaveBeenCalledWith(
  116. '/organizations/org-slug/events-stats/',
  117. expect.objectContaining({
  118. query: expect.objectContaining({
  119. dataset: 'metrics',
  120. }),
  121. })
  122. );
  123. });
  124. expect(eventsMock).toHaveBeenCalledWith(
  125. '/organizations/org-slug/events/',
  126. expect.objectContaining({
  127. query: expect.objectContaining({
  128. dataset: 'metrics',
  129. }),
  130. })
  131. );
  132. expect(screen.getByText(/Processed events/i)).toBeInTheDocument();
  133. expect(screen.getByText(/19m/i)).toBeInTheDocument();
  134. expect(screen.getByTestId('processed-events-toggle')).toBeEnabled();
  135. });
  136. it('displays metrics baseline', async function () {
  137. addMetricsDataMock();
  138. const organization = TestStubs.Organization({
  139. features: [
  140. ...features,
  141. 'discover-metrics-baseline',
  142. 'server-side-sampling',
  143. 'mep-rollout-flag',
  144. ],
  145. });
  146. const yAxis = ['p50(transaction.duration)'];
  147. renderMetricsBaselineContainer(organization, project, eventView, yAxis);
  148. await waitFor(() => {
  149. expect(eventsStatsMock).toHaveBeenCalledWith(
  150. '/organizations/org-slug/events-stats/',
  151. expect.objectContaining({
  152. query: expect.objectContaining({
  153. dataset: 'metrics',
  154. }),
  155. })
  156. );
  157. });
  158. expect(screen.getByText(/Processed events/i)).toBeInTheDocument();
  159. expect(screen.getByTestId('processed-events-toggle')).toBeEnabled();
  160. await waitFor(() => {
  161. expect(ReactEchartsCore).toHaveBeenLastCalledWith(
  162. expect.objectContaining({
  163. option: expect.objectContaining({
  164. legend: expect.objectContaining({
  165. data: expect.arrayContaining([
  166. 'processed events: p50(transaction.duration)',
  167. ]),
  168. }),
  169. }),
  170. }),
  171. {}
  172. );
  173. });
  174. });
  175. it('disables processed baseline toggle if metrics cardinality conditions not met', function () {
  176. const organization = TestStubs.Organization({
  177. features: [...features, 'discover-metrics-baseline'],
  178. });
  179. const yAxis = ['p50(transaction.duration)'];
  180. renderMetricsBaselineContainer(organization, project, eventView, yAxis);
  181. expect(screen.getByText(/Processed events/i)).toBeInTheDocument();
  182. expect(screen.getByTestId('processed-events-toggle')).toBeDisabled();
  183. });
  184. it('disables toggle if discover hits the events dataset', function () {
  185. addMetricsDataMock();
  186. const organization = TestStubs.Organization({
  187. features: [
  188. ...features,
  189. 'discover-metrics-baseline',
  190. 'server-side-sampling',
  191. 'mep-rollout-flag',
  192. ],
  193. });
  194. const yAxis = ['count()'];
  195. renderMetricsBaselineContainer(organization, project, eventView, yAxis);
  196. expect(screen.getByText(/Processed events/i)).toBeInTheDocument();
  197. expect(screen.getByTestId('processed-events-toggle')).toBeDisabled();
  198. });
  199. it('pushes toggle selection to URL', async function () {
  200. addMetricsDataMock();
  201. const organization = TestStubs.Organization({
  202. features: [
  203. ...features,
  204. 'discover-metrics-baseline',
  205. 'server-side-sampling',
  206. 'mep-rollout-flag',
  207. ],
  208. });
  209. const yAxis = ['p50(transaction.duration)'];
  210. const router = renderMetricsBaselineContainer(
  211. organization,
  212. project,
  213. eventView,
  214. yAxis
  215. );
  216. await waitFor(() => {
  217. expect(eventsStatsMock).toHaveBeenCalledWith(
  218. '/organizations/org-slug/events-stats/',
  219. expect.objectContaining({
  220. query: expect.objectContaining({
  221. dataset: 'metrics',
  222. }),
  223. })
  224. );
  225. });
  226. expect(screen.getByTestId('processed-events-toggle')).toBeEnabled();
  227. expect(screen.getByTestId('processed-events-toggle')).toBeChecked();
  228. userEvent.click(screen.getByTestId('processed-events-toggle'));
  229. expect(router.push).toHaveBeenCalledWith(
  230. expect.objectContaining({query: expect.objectContaining({baseline: '0'})})
  231. );
  232. });
  233. });