useDiscover.spec.tsx 8.1 KB

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