queryBatcher.spec.tsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. import {Fragment} from 'react';
  2. import {initializeData as _initializeData} from 'sentry-test/performance/initializePerformanceData';
  3. import {mountWithTheme, screen} from 'sentry-test/reactTestingLibrary';
  4. import {GenericQueryBatcher} from 'sentry/utils/performance/contexts/genericQueryBatcher';
  5. import {PerformanceDisplayProvider} from 'sentry/utils/performance/contexts/performanceDisplayContext';
  6. import WidgetContainer from 'sentry/views/performance/landing/widgets/components/widgetContainer';
  7. import {PerformanceWidgetSetting} from 'sentry/views/performance/landing/widgets/widgetDefinitions';
  8. import {PROJECT_PERFORMANCE_TYPE} from 'sentry/views/performance/utils';
  9. const initializeData = () => {
  10. const data = _initializeData({
  11. query: {statsPeriod: '7d', environment: ['prod'], project: [-42]},
  12. });
  13. data.eventView.additionalConditions.addFilterValues('transaction.op', ['pageload']);
  14. return data;
  15. };
  16. const BASIC_QUERY_PARAMS = {
  17. interval: '1h',
  18. partial: '1',
  19. query: 'transaction.op:pageload',
  20. statsPeriod: '14d',
  21. };
  22. const WrappedComponent = ({data, ...rest}) => {
  23. return (
  24. <PerformanceDisplayProvider value={{performanceType: PROJECT_PERFORMANCE_TYPE.ANY}}>
  25. <WidgetContainer
  26. allowedCharts={[
  27. PerformanceWidgetSetting.TPM_AREA,
  28. PerformanceWidgetSetting.FAILURE_RATE_AREA,
  29. PerformanceWidgetSetting.USER_MISERY_AREA,
  30. ]}
  31. rowChartSettings={[]}
  32. forceDefaultChartSetting
  33. {...data}
  34. {...rest}
  35. />
  36. </PerformanceDisplayProvider>
  37. );
  38. };
  39. describe('Performance > Widgets > Query Batching', function () {
  40. let eventStatsMock;
  41. beforeEach(function () {
  42. eventStatsMock = MockApiClient.addMockResponse({
  43. method: 'GET',
  44. url: `/organizations/org-slug/events-stats/`,
  45. body: {
  46. 'tpm()': {
  47. data: [
  48. [
  49. 1636822800,
  50. [
  51. {
  52. count: 30.0,
  53. },
  54. ],
  55. ],
  56. [
  57. 1636995600,
  58. [
  59. {
  60. count: 60.1,
  61. },
  62. ],
  63. ],
  64. ],
  65. order: 1,
  66. start: 1636822800,
  67. end: 1636995600,
  68. },
  69. 'user_misery()': {
  70. data: [
  71. [
  72. 1636822800,
  73. [
  74. {
  75. count: 0.02,
  76. },
  77. ],
  78. ],
  79. [
  80. 1636995600,
  81. [
  82. {
  83. count: 0.03,
  84. },
  85. ],
  86. ],
  87. ],
  88. order: 1,
  89. start: 1636822800,
  90. end: 1636995600,
  91. },
  92. 'failure_rate()': {
  93. data: [
  94. [
  95. 1636822800,
  96. [
  97. {
  98. count: 0.002,
  99. },
  100. ],
  101. ],
  102. [
  103. 1636995600,
  104. [
  105. {
  106. count: 0.001,
  107. },
  108. ],
  109. ],
  110. ],
  111. order: 2,
  112. start: 1636822800,
  113. end: 1636995600,
  114. },
  115. },
  116. });
  117. });
  118. it('EventsRequest based component fires query without provider', async function () {
  119. const data = initializeData();
  120. mountWithTheme(
  121. <WrappedComponent
  122. data={data}
  123. defaultChartSetting={PerformanceWidgetSetting.TPM_AREA}
  124. />,
  125. {
  126. organization: data.organization,
  127. }
  128. );
  129. expect(await screen.findByTestId('performance-widget-title')).toBeInTheDocument();
  130. expect(eventStatsMock).toHaveBeenCalledTimes(1);
  131. expect(eventStatsMock).toHaveBeenNthCalledWith(
  132. 1,
  133. expect.anything(),
  134. expect.objectContaining({
  135. query: expect.objectContaining({
  136. ...BASIC_QUERY_PARAMS,
  137. yAxis: 'tpm()',
  138. }),
  139. })
  140. );
  141. });
  142. it('Multiple EventsRequest based components fire individual queries without provider', async function () {
  143. const data = initializeData();
  144. mountWithTheme(
  145. <Fragment>
  146. <WrappedComponent
  147. data={data}
  148. defaultChartSetting={PerformanceWidgetSetting.TPM_AREA}
  149. />
  150. <WrappedComponent
  151. data={data}
  152. defaultChartSetting={PerformanceWidgetSetting.FAILURE_RATE_AREA}
  153. />
  154. <WrappedComponent
  155. data={data}
  156. defaultChartSetting={PerformanceWidgetSetting.USER_MISERY_AREA}
  157. />
  158. </Fragment>,
  159. {
  160. organization: data.organization,
  161. }
  162. );
  163. expect(await screen.findAllByTestId('performance-widget-title')).toHaveLength(3);
  164. // Three requests are made
  165. expect(eventStatsMock).toHaveBeenCalledTimes(3);
  166. expect(eventStatsMock).toHaveBeenNthCalledWith(
  167. 1,
  168. expect.anything(),
  169. expect.objectContaining({
  170. query: expect.objectContaining({
  171. ...BASIC_QUERY_PARAMS,
  172. yAxis: 'tpm()',
  173. }),
  174. })
  175. );
  176. });
  177. it('Multiple EventsRequest based component merge queries with provider ', async function () {
  178. const data = initializeData();
  179. mountWithTheme(
  180. <GenericQueryBatcher>
  181. <WrappedComponent
  182. data={data}
  183. defaultChartSetting={PerformanceWidgetSetting.TPM_AREA}
  184. />
  185. <WrappedComponent
  186. data={data}
  187. defaultChartSetting={PerformanceWidgetSetting.FAILURE_RATE_AREA}
  188. />
  189. <WrappedComponent
  190. data={data}
  191. defaultChartSetting={PerformanceWidgetSetting.USER_MISERY_AREA}
  192. />
  193. </GenericQueryBatcher>,
  194. {
  195. organization: data.organization,
  196. }
  197. );
  198. expect(await screen.findAllByTestId('performance-widget-title')).toHaveLength(3);
  199. expect(eventStatsMock).toHaveBeenNthCalledWith(
  200. 1,
  201. expect.anything(),
  202. expect.objectContaining({
  203. query: expect.objectContaining({
  204. ...BASIC_QUERY_PARAMS,
  205. yAxis: ['tpm()', 'failure_rate()', 'user_misery()'],
  206. }),
  207. })
  208. );
  209. expect(eventStatsMock).toHaveBeenCalledTimes(1);
  210. expect(await screen.findAllByTestId('widget-state-has-data')).toHaveLength(3);
  211. });
  212. it('Errors work correctly', async function () {
  213. eventStatsMock = MockApiClient.addMockResponse({
  214. method: 'GET',
  215. url: `/organizations/org-slug/events-stats/`,
  216. statusCode: 404,
  217. body: {},
  218. });
  219. const data = initializeData();
  220. mountWithTheme(
  221. <GenericQueryBatcher>
  222. <WrappedComponent
  223. data={data}
  224. defaultChartSetting={PerformanceWidgetSetting.TPM_AREA}
  225. />
  226. <WrappedComponent
  227. data={data}
  228. defaultChartSetting={PerformanceWidgetSetting.FAILURE_RATE_AREA}
  229. />
  230. <WrappedComponent
  231. data={data}
  232. defaultChartSetting={PerformanceWidgetSetting.USER_MISERY_AREA}
  233. />
  234. </GenericQueryBatcher>,
  235. {
  236. organization: data.organization,
  237. }
  238. );
  239. expect(await screen.findAllByTestId('performance-widget-title')).toHaveLength(3);
  240. expect(eventStatsMock).toHaveBeenNthCalledWith(
  241. 1,
  242. expect.anything(),
  243. expect.objectContaining({
  244. query: expect.objectContaining({
  245. ...BASIC_QUERY_PARAMS,
  246. yAxis: ['tpm()', 'failure_rate()', 'user_misery()'],
  247. }),
  248. })
  249. );
  250. expect(eventStatsMock).toHaveBeenCalledTimes(1);
  251. expect(await screen.findAllByTestId('widget-state-is-errored')).toHaveLength(3);
  252. });
  253. });