metricsDataSwitcher.spec.tsx 11 KB

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