spanDescription.spec.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import {OrganizationFixture} from 'sentry-fixture/organization';
  2. import {ProjectFixture} from 'sentry-fixture/project';
  3. import {render, screen, waitForElementToBeRemoved} from 'sentry-test/reactTestingLibrary';
  4. import {textWithMarkupMatcher} from 'sentry-test/utils';
  5. import {EntryType} from 'sentry/types/event';
  6. import usePageFilters from 'sentry/utils/usePageFilters';
  7. import {DatabaseSpanDescription} from 'sentry/views/insights/common/components/spanDescription';
  8. jest.mock('sentry/utils/usePageFilters');
  9. describe('DatabaseSpanDescription', function () {
  10. beforeEach(() => {
  11. jest.clearAllMocks();
  12. });
  13. const organization = OrganizationFixture();
  14. const project = ProjectFixture();
  15. jest.mocked(usePageFilters).mockReturnValue({
  16. isReady: true,
  17. desyncedFilters: new Set(),
  18. pinnedFilters: new Set(),
  19. shouldPersist: true,
  20. selection: {
  21. datetime: {
  22. period: '10d',
  23. start: null,
  24. end: null,
  25. utc: false,
  26. },
  27. environments: [],
  28. projects: [],
  29. },
  30. });
  31. const groupId = '2ed2abf6ce7e3577';
  32. const spanId = 'abfed2aabf';
  33. const eventId = '65c7d8647b8a76ef8f4c05d41deb7860';
  34. it('shows preliminary description if no more data is available', async function () {
  35. MockApiClient.addMockResponse({
  36. url: `/organizations/${organization.slug}/events/`,
  37. body: [],
  38. });
  39. render(
  40. <DatabaseSpanDescription
  41. groupId={groupId}
  42. preliminaryDescription="SELECT USERS FRO*"
  43. />,
  44. {organization}
  45. );
  46. await waitForElementToBeRemoved(() => screen.getByTestId('loading-indicator'));
  47. expect(screen.getByText('SELECT USERS FRO*')).toBeInTheDocument();
  48. });
  49. it('shows full query if full event is available', async function () {
  50. MockApiClient.addMockResponse({
  51. url: `/organizations/${organization.slug}/events/`,
  52. body: {
  53. data: [
  54. {
  55. 'transaction.id': eventId,
  56. project: project.slug,
  57. span_id: spanId,
  58. },
  59. ],
  60. },
  61. });
  62. MockApiClient.addMockResponse({
  63. url: `/organizations/${organization.slug}/events/${project.slug}:${eventId}/`,
  64. body: {
  65. id: eventId,
  66. entries: [
  67. {
  68. type: EntryType.SPANS,
  69. data: [
  70. {
  71. span_id: spanId,
  72. description: 'SELECT users FROM my_table LIMIT 1;',
  73. },
  74. ],
  75. },
  76. ],
  77. },
  78. });
  79. render(
  80. <DatabaseSpanDescription
  81. groupId={groupId}
  82. preliminaryDescription="SELECT USERS FRO*"
  83. />,
  84. {organization}
  85. );
  86. await waitForElementToBeRemoved(() => screen.getByTestId('loading-indicator'));
  87. expect(
  88. await screen.findByText('SELECT users FROM my_table LIMIT 1;')
  89. ).toBeInTheDocument();
  90. });
  91. it('shows query source if available', async function () {
  92. MockApiClient.addMockResponse({
  93. url: `/organizations/${organization.slug}/events/`,
  94. body: {
  95. data: [
  96. {
  97. 'transaction.id': eventId,
  98. project: project.slug,
  99. span_id: spanId,
  100. },
  101. ],
  102. },
  103. });
  104. MockApiClient.addMockResponse({
  105. url: `/organizations/${organization.slug}/events/${project.slug}:${eventId}/`,
  106. body: {
  107. id: eventId,
  108. entries: [
  109. {
  110. type: EntryType.SPANS,
  111. data: [
  112. {
  113. span_id: spanId,
  114. description: 'SELECT users FROM my_table LIMIT 1;',
  115. data: {
  116. 'code.filepath': '/app/views/users.py',
  117. 'code.lineno': 78,
  118. },
  119. },
  120. ],
  121. },
  122. ],
  123. },
  124. });
  125. render(
  126. <DatabaseSpanDescription
  127. groupId={groupId}
  128. preliminaryDescription="SELECT USERS FRO*"
  129. />,
  130. {organization}
  131. );
  132. await waitForElementToBeRemoved(() => screen.getByTestId('loading-indicator'));
  133. expect(
  134. await screen.findByText('SELECT users FROM my_table LIMIT 1;')
  135. ).toBeInTheDocument();
  136. expect(
  137. screen.getByText(textWithMarkupMatcher('/app/views/users.py at line 78'))
  138. ).toBeInTheDocument();
  139. });
  140. it('correctly formats and displays MongoDB queries', async function () {
  141. MockApiClient.addMockResponse({
  142. url: `/organizations/${organization.slug}/events/`,
  143. body: {
  144. data: [
  145. {
  146. 'transaction.id': eventId,
  147. project: project.slug,
  148. span_id: spanId,
  149. },
  150. ],
  151. },
  152. });
  153. const sampleMongoDBQuery = `{"a": "?", "insert": "documents"}`;
  154. MockApiClient.addMockResponse({
  155. url: `/organizations/${organization.slug}/events/${project.slug}:${eventId}/`,
  156. body: {
  157. id: eventId,
  158. entries: [
  159. {
  160. type: EntryType.SPANS,
  161. data: [
  162. {
  163. span_id: spanId,
  164. description: sampleMongoDBQuery,
  165. data: {
  166. 'db.system': 'mongodb',
  167. },
  168. },
  169. ],
  170. },
  171. ],
  172. },
  173. });
  174. render(
  175. <DatabaseSpanDescription
  176. groupId={groupId}
  177. preliminaryDescription={sampleMongoDBQuery}
  178. />,
  179. {organization}
  180. );
  181. await waitForElementToBeRemoved(() => screen.getByTestId('loading-indicator'));
  182. // expect(await screen.findBy).toBeInTheDocument();
  183. const mongoQuerySnippet = await screen.findByText(
  184. /\{ "a": "\?", "insert": "documents" \}/i
  185. );
  186. expect(mongoQuerySnippet).toBeInTheDocument();
  187. expect(mongoQuerySnippet).toHaveClass('language-json');
  188. });
  189. });