useDiscover.spec.tsx 8.2 KB

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