useDiscover.spec.tsx 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. import type {ReactNode} from 'react';
  2. import {LocationFixture} from 'sentry-fixture/locationFixture';
  3. import {OrganizationFixture} from 'sentry-fixture/organization';
  4. import {makeTestQueryClient} from 'sentry-test/queryClient';
  5. import {renderHook, waitFor} from 'sentry-test/reactTestingLibrary';
  6. import {QueryClientProvider} from 'sentry/utils/queryClient';
  7. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  8. import {useLocation} from 'sentry/utils/useLocation';
  9. import usePageFilters from 'sentry/utils/usePageFilters';
  10. import {
  11. useSpanMetrics,
  12. useSpansIndexed,
  13. } from 'sentry/views/insights/common/queries/useDiscover';
  14. import {SpanIndexedField, type SpanMetricsProperty} from 'sentry/views/insights/types';
  15. import {OrganizationContext} from 'sentry/views/organizationContext';
  16. jest.mock('sentry/utils/useLocation');
  17. jest.mock('sentry/utils/usePageFilters');
  18. function Wrapper({children}: {children?: ReactNode}) {
  19. return (
  20. <QueryClientProvider client={makeTestQueryClient()}>
  21. <OrganizationContext.Provider value={OrganizationFixture()}>
  22. {children}
  23. </OrganizationContext.Provider>
  24. </QueryClientProvider>
  25. );
  26. }
  27. describe('useDiscover', () => {
  28. describe('useSpanMetrics', () => {
  29. const organization = OrganizationFixture();
  30. jest.mocked(usePageFilters).mockReturnValue({
  31. isReady: true,
  32. desyncedFilters: new Set(),
  33. pinnedFilters: new Set(),
  34. shouldPersist: true,
  35. selection: {
  36. datetime: {
  37. period: '10d',
  38. start: null,
  39. end: null,
  40. utc: false,
  41. },
  42. environments: [],
  43. projects: [],
  44. },
  45. });
  46. jest.mocked(useLocation).mockReturnValue(
  47. LocationFixture({
  48. query: {statsPeriod: '10d'},
  49. })
  50. );
  51. it('respects the `enabled` prop', () => {
  52. const eventsRequest = MockApiClient.addMockResponse({
  53. url: `/organizations/${organization.slug}/events/`,
  54. method: 'GET',
  55. body: {data: []},
  56. });
  57. const {result} = renderHook(
  58. ({fields, enabled}) => useSpanMetrics({fields, enabled}, 'span-metrics-series'),
  59. {
  60. wrapper: Wrapper,
  61. initialProps: {
  62. fields: ['spm()'] as SpanMetricsProperty[],
  63. enabled: false,
  64. },
  65. }
  66. );
  67. expect(result.current.isFetching).toEqual(false);
  68. expect(eventsRequest).not.toHaveBeenCalled();
  69. });
  70. it('queries for current selection', async () => {
  71. const eventsRequest = MockApiClient.addMockResponse({
  72. url: `/organizations/${organization.slug}/events/`,
  73. method: 'GET',
  74. body: {
  75. data: [
  76. {
  77. 'span.op': 'db',
  78. 'spm()': 1486.3201388888888,
  79. 'count()': 2140301,
  80. },
  81. ],
  82. },
  83. });
  84. const {result} = renderHook(
  85. ({filters, fields, sorts, limit, cursor, referrer}) =>
  86. useSpanMetrics(
  87. {
  88. search: MutableSearch.fromQueryObject(filters),
  89. fields,
  90. sorts,
  91. limit,
  92. cursor,
  93. },
  94. referrer
  95. ),
  96. {
  97. wrapper: Wrapper,
  98. initialProps: {
  99. filters: {
  100. 'span.group': '221aa7ebd216',
  101. transaction: '/api/details',
  102. release: '0.0.1',
  103. environment: undefined,
  104. },
  105. fields: ['spm()'] as SpanMetricsProperty[],
  106. sorts: [{field: 'spm()', kind: 'desc' as const}],
  107. limit: 10,
  108. referrer: 'api-spec',
  109. cursor: undefined,
  110. },
  111. }
  112. );
  113. expect(result.current.isPending).toEqual(true);
  114. expect(eventsRequest).toHaveBeenCalledWith(
  115. '/organizations/org-slug/events/',
  116. expect.objectContaining({
  117. method: 'GET',
  118. query: {
  119. dataset: 'spansMetrics',
  120. environment: [],
  121. field: ['spm()'],
  122. per_page: 10,
  123. project: [],
  124. sort: '-spm()',
  125. query: `span.group:221aa7ebd216 transaction:/api/details release:0.0.1`,
  126. referrer: 'api-spec',
  127. statsPeriod: '10d',
  128. },
  129. })
  130. );
  131. await waitFor(() => expect(result.current.isPending).toEqual(false));
  132. expect(result.current.data).toEqual([
  133. {
  134. 'span.op': 'db',
  135. 'spm()': 1486.3201388888888,
  136. 'count()': 2140301,
  137. },
  138. ]);
  139. });
  140. });
  141. describe('useSpanIndexed', () => {
  142. const organization = OrganizationFixture();
  143. jest.mocked(usePageFilters).mockReturnValue({
  144. isReady: true,
  145. desyncedFilters: new Set(),
  146. pinnedFilters: new Set(),
  147. shouldPersist: true,
  148. selection: {
  149. datetime: {
  150. period: '10d',
  151. start: null,
  152. end: null,
  153. utc: false,
  154. },
  155. environments: [],
  156. projects: [],
  157. },
  158. });
  159. jest.mocked(useLocation).mockReturnValue(
  160. LocationFixture({
  161. query: {statsPeriod: '10d'},
  162. })
  163. );
  164. beforeEach(() => {
  165. jest.clearAllMocks();
  166. });
  167. it('respects the `enabled` prop', () => {
  168. const eventsRequest = MockApiClient.addMockResponse({
  169. url: `/organizations/${organization.slug}/events/`,
  170. method: 'GET',
  171. body: {data: []},
  172. });
  173. const {result} = renderHook(
  174. ({fields, enabled}) => useSpansIndexed({fields, enabled}, 'referrer'),
  175. {
  176. wrapper: Wrapper,
  177. initialProps: {
  178. fields: [SpanIndexedField.SPAN_DESCRIPTION],
  179. enabled: false,
  180. },
  181. }
  182. );
  183. expect(result.current.isFetching).toEqual(false);
  184. expect(eventsRequest).not.toHaveBeenCalled();
  185. });
  186. it('queries for current selection', async () => {
  187. const eventsRequest = MockApiClient.addMockResponse({
  188. url: `/organizations/${organization.slug}/events/`,
  189. method: 'GET',
  190. body: {
  191. data: [
  192. {
  193. 'span.group': '221aa7ebd216',
  194. 'span.op': 'db',
  195. 'span.description': 'SELECT * FROM users;',
  196. },
  197. ],
  198. meta: {
  199. fields: {
  200. 'span.description': 'string',
  201. 'span.op': 'string',
  202. 'span.group': 'string',
  203. },
  204. },
  205. },
  206. });
  207. const {result} = renderHook(
  208. ({filters, fields, sorts, limit, cursor, referrer}) =>
  209. useSpansIndexed(
  210. {
  211. search: MutableSearch.fromQueryObject(filters),
  212. fields,
  213. sorts,
  214. limit,
  215. cursor,
  216. },
  217. referrer
  218. ),
  219. {
  220. wrapper: Wrapper,
  221. initialProps: {
  222. filters: {
  223. 'span.group': '221aa7ebd216',
  224. 'measurements.inp': ['<50', '>0'],
  225. transaction: '/api/details',
  226. release: '0.0.1',
  227. },
  228. fields: [
  229. SpanIndexedField.SPAN_OP,
  230. SpanIndexedField.SPAN_GROUP,
  231. SpanIndexedField.SPAN_DESCRIPTION,
  232. ],
  233. sorts: [{field: 'span.group', kind: 'desc' as const}],
  234. limit: 10,
  235. referrer: 'api-spec',
  236. cursor: undefined,
  237. },
  238. }
  239. );
  240. expect(result.current.isPending).toEqual(true);
  241. expect(eventsRequest).toHaveBeenCalledWith(
  242. '/organizations/org-slug/events/',
  243. expect.objectContaining({
  244. method: 'GET',
  245. query: {
  246. dataset: 'spansIndexed',
  247. environment: [],
  248. field: ['span.op', 'span.group', 'span.description'],
  249. per_page: 10,
  250. project: [],
  251. sort: '-span.group',
  252. query: `span.group:221aa7ebd216 measurements.inp:<50 measurements.inp:>0 transaction:/api/details release:0.0.1`,
  253. referrer: 'api-spec',
  254. statsPeriod: '10d',
  255. },
  256. })
  257. );
  258. await waitFor(() => expect(result.current.isPending).toEqual(false));
  259. expect(result.current.data).toEqual([
  260. {
  261. 'span.group': '221aa7ebd216',
  262. 'span.op': 'db',
  263. 'span.description': 'SELECT * FROM users;',
  264. },
  265. ]);
  266. });
  267. });
  268. });