metricsDataSwitcher.spec.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. import {initializeData} from 'sentry-test/performance/initializePerformanceData';
  2. import {act, render, screen} from 'sentry-test/reactTestingLibrary';
  3. import TeamStore from 'sentry/stores/teamStore';
  4. import {MetricsCardinalityProvider} from 'sentry/utils/performance/contexts/metricsCardinality';
  5. import {OrganizationContext} from 'sentry/views/organizationContext';
  6. import {generatePerformanceEventView} from 'sentry/views/performance/data';
  7. import {PerformanceLanding} from 'sentry/views/performance/landing';
  8. export function addMetricsDataMock(settings?: {
  9. metricsCount: number;
  10. nullCount: number;
  11. unparamCount: number;
  12. compatibleProjects?: number[];
  13. dynamicSampledProjects?: number[];
  14. }) {
  15. const compatible_projects = settings?.compatibleProjects ?? [];
  16. const metricsCount = settings?.metricsCount ?? 10;
  17. const unparamCount = settings?.unparamCount ?? 0;
  18. const nullCount = settings?.nullCount ?? 0;
  19. const dynamic_sampling_projects = settings?.dynamicSampledProjects ?? [1];
  20. MockApiClient.addMockResponse({
  21. method: 'GET',
  22. url: `/organizations/org-slug/metrics-compatibility/`,
  23. body: {
  24. compatible_projects,
  25. dynamic_sampling_projects,
  26. },
  27. });
  28. MockApiClient.addMockResponse({
  29. method: 'GET',
  30. url: `/organizations/org-slug/metrics-compatibility-sums/`,
  31. body: {
  32. sum: {
  33. metrics: metricsCount,
  34. metrics_unparam: unparamCount,
  35. metrics_null: nullCount,
  36. },
  37. },
  38. });
  39. MockApiClient.addMockResponse({
  40. method: 'GET',
  41. url: `/organizations/org-slug/events/`,
  42. body: {
  43. data: [{}],
  44. meta: {},
  45. },
  46. });
  47. }
  48. const WrappedComponent = ({data, withStaticFilters = true}) => {
  49. const eventView = generatePerformanceEventView(data.router.location, data.projects, {
  50. withStaticFilters,
  51. });
  52. return (
  53. <OrganizationContext.Provider value={data.organization}>
  54. <MetricsCardinalityProvider
  55. location={data.router.location}
  56. organization={data.organization}
  57. >
  58. <PerformanceLanding
  59. router={data.router}
  60. organization={data.organization}
  61. location={data.router.location}
  62. eventView={eventView}
  63. projects={data.projects}
  64. selection={eventView.getPageFilters()}
  65. onboardingProject={undefined}
  66. handleSearch={() => {}}
  67. handleTrendsClick={() => {}}
  68. setError={() => {}}
  69. withStaticFilters={withStaticFilters}
  70. />
  71. </MetricsCardinalityProvider>
  72. </OrganizationContext.Provider>
  73. );
  74. };
  75. const features = [
  76. 'performance-transaction-name-only-search',
  77. 'organizations:performance-transaction-name-only-search',
  78. ];
  79. describe('Performance > Landing > MetricsDataSwitcher', function () {
  80. let wrapper: any;
  81. act(() => void TeamStore.loadInitialData([], false, null));
  82. beforeEach(function () {
  83. // @ts-ignore no-console
  84. // eslint-disable-next-line no-console
  85. jest.spyOn(console, 'error').mockImplementation(jest.fn());
  86. MockApiClient.addMockResponse({
  87. url: '/organizations/org-slug/sdk-updates/',
  88. body: [],
  89. });
  90. MockApiClient.addMockResponse({
  91. url: '/prompts-activity/',
  92. body: {},
  93. });
  94. MockApiClient.addMockResponse({
  95. url: '/organizations/org-slug/projects/',
  96. body: [],
  97. });
  98. MockApiClient.addMockResponse({
  99. method: 'GET',
  100. url: `/organizations/org-slug/key-transactions-list/`,
  101. body: [],
  102. });
  103. MockApiClient.addMockResponse({
  104. method: 'GET',
  105. url: `/organizations/org-slug/legacy-key-transactions-count/`,
  106. body: [],
  107. });
  108. MockApiClient.addMockResponse({
  109. method: 'GET',
  110. url: `/organizations/org-slug/events-stats/`,
  111. body: [],
  112. });
  113. MockApiClient.addMockResponse({
  114. method: 'GET',
  115. url: `/organizations/org-slug/events-trends-stats/`,
  116. body: [],
  117. });
  118. MockApiClient.addMockResponse({
  119. method: 'GET',
  120. url: `/organizations/org-slug/events-histogram/`,
  121. body: [],
  122. });
  123. MockApiClient.addMockResponse({
  124. method: 'GET',
  125. url: `/organizations/org-slug/eventsv2/`,
  126. body: {
  127. meta: {
  128. id: 'string',
  129. },
  130. data: [
  131. {
  132. id: '1234',
  133. },
  134. ],
  135. },
  136. });
  137. });
  138. afterEach(function () {
  139. MockApiClient.clearMockResponses();
  140. // @ts-ignore no-console
  141. // eslint-disable-next-line no-console
  142. console.error.mockRestore();
  143. if (wrapper) {
  144. wrapper.unmount();
  145. wrapper = undefined;
  146. }
  147. });
  148. it('renders basic UI elements', function () {
  149. addMetricsDataMock();
  150. const project = TestStubs.Project();
  151. const data = initializeData({
  152. project: project.id,
  153. projects: [project],
  154. features,
  155. });
  156. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  157. expect(screen.getByTestId('performance-landing-v3')).toBeInTheDocument();
  158. });
  159. it('renders with feature flag and all metric data', async function () {
  160. addMetricsDataMock();
  161. const project = TestStubs.Project();
  162. const data = initializeData({
  163. project: project.id,
  164. projects: [project],
  165. features,
  166. });
  167. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  168. expect(await screen.findByTestId('transaction-search-bar')).toBeInTheDocument();
  169. });
  170. it('renders with feature flag and no metrics data', async function () {
  171. addMetricsDataMock({
  172. metricsCount: 0,
  173. nullCount: 0,
  174. unparamCount: 0,
  175. });
  176. const project = TestStubs.Project();
  177. const data = initializeData({
  178. project: project.id,
  179. projects: [project],
  180. features,
  181. });
  182. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  183. expect(await screen.findByTestId('smart-search-bar')).toBeInTheDocument();
  184. });
  185. it('renders with feature flag and checking dynamic sampled projects exist', async function () {
  186. addMetricsDataMock({
  187. metricsCount: 100,
  188. nullCount: 0,
  189. unparamCount: 0,
  190. });
  191. const project = TestStubs.Project();
  192. const data = initializeData({
  193. project: project.id,
  194. projects: [project],
  195. features,
  196. });
  197. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  198. expect(await screen.findByTestId('transaction-search-bar')).toBeInTheDocument();
  199. });
  200. it('renders with feature flag and any incompatible data', async function () {
  201. addMetricsDataMock({
  202. metricsCount: 100,
  203. nullCount: 1,
  204. unparamCount: 0,
  205. });
  206. const project = TestStubs.Project();
  207. const data = initializeData({
  208. project: project.id,
  209. projects: [project],
  210. features,
  211. });
  212. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  213. expect(await screen.findByTestId('smart-search-bar')).toBeInTheDocument();
  214. expect(
  215. await screen.findByTestId('landing-mep-alert-single-project-incompatible')
  216. ).toBeInTheDocument();
  217. });
  218. it('renders with feature flag and any incompatible transactions on multiple projects with at least one compatible project', async function () {
  219. addMetricsDataMock({
  220. metricsCount: 100,
  221. nullCount: 1,
  222. unparamCount: 0,
  223. compatibleProjects: [1],
  224. });
  225. const project = TestStubs.Project({id: 1});
  226. const project2 = TestStubs.Project({id: 2});
  227. const data = initializeData({
  228. project: '-1',
  229. projects: [project, project2],
  230. features,
  231. });
  232. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  233. expect(await screen.findByTestId('smart-search-bar')).toBeInTheDocument();
  234. expect(
  235. await screen.findByTestId('landing-mep-alert-multi-project-incompatible')
  236. ).toBeInTheDocument();
  237. });
  238. it('renders with feature flag and any incompatible transactions on multiple projects with no compatible project', async function () {
  239. addMetricsDataMock({
  240. metricsCount: 100,
  241. nullCount: 1,
  242. unparamCount: 0,
  243. compatibleProjects: [],
  244. });
  245. const project = TestStubs.Project({id: 1});
  246. const project2 = TestStubs.Project({id: 2});
  247. const data = initializeData({
  248. project: '-1',
  249. projects: [project, project2],
  250. features,
  251. });
  252. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  253. expect(await screen.findByTestId('smart-search-bar')).toBeInTheDocument();
  254. expect(
  255. await screen.findByTestId('landing-mep-alert-multi-project-all-incompatible')
  256. ).toBeInTheDocument();
  257. });
  258. it('renders with feature flag and all other(unparam) transactions', async function () {
  259. addMetricsDataMock({
  260. metricsCount: 100,
  261. nullCount: 0,
  262. unparamCount: 100,
  263. });
  264. const project = TestStubs.Project();
  265. const data = initializeData({
  266. project: project.id,
  267. projects: [project],
  268. features,
  269. });
  270. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  271. expect(await screen.findByTestId('smart-search-bar')).toBeInTheDocument();
  272. expect(
  273. await screen.findByTestId('landing-mep-alert-unnamed-discover')
  274. ).toBeInTheDocument();
  275. });
  276. it('renders with feature flag and partial other(unparam) transactions and platform with docs', async function () {
  277. addMetricsDataMock({
  278. metricsCount: 100,
  279. nullCount: 0,
  280. unparamCount: 1,
  281. });
  282. const platformWithDocs = 'javascript.react';
  283. const project = TestStubs.Project({platform: platformWithDocs});
  284. const data = initializeData({
  285. project: project.id,
  286. projects: [project],
  287. features,
  288. });
  289. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  290. expect(await screen.findByTestId('transaction-search-bar')).toBeInTheDocument();
  291. expect(
  292. await screen.findByTestId('landing-mep-alert-unnamed-discover-or-set')
  293. ).toBeInTheDocument();
  294. });
  295. it('renders with feature flag and partial other(unparam) transactions', async function () {
  296. addMetricsDataMock({
  297. metricsCount: 100,
  298. nullCount: 0,
  299. unparamCount: 1,
  300. });
  301. const project = TestStubs.Project();
  302. const data = initializeData({
  303. project: project.id,
  304. projects: [project],
  305. features,
  306. });
  307. wrapper = render(<WrappedComponent data={data} />, data.routerContext);
  308. expect(await screen.findByTestId('transaction-search-bar')).toBeInTheDocument();
  309. expect(
  310. await screen.findByTestId('landing-mep-alert-unnamed-discover')
  311. ).toBeInTheDocument();
  312. });
  313. });