fullSpanDescription.spec.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 {EntryType} from 'sentry/types/event';
  5. import usePageFilters from 'sentry/utils/usePageFilters';
  6. import {FullSpanDescription} from 'sentry/views/insights/common/components/fullSpanDescription';
  7. import {ModuleName} from 'sentry/views/insights/types';
  8. jest.mock('sentry/utils/usePageFilters');
  9. describe('FullSpanDescription', 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('uses the correct code formatting for SQL queries', async function () {
  35. MockApiClient.addMockResponse({
  36. url: `/organizations/${organization.slug}/events/`,
  37. body: {
  38. data: [
  39. {
  40. 'transaction.id': eventId,
  41. project: project.slug,
  42. span_id: spanId,
  43. },
  44. ],
  45. },
  46. });
  47. MockApiClient.addMockResponse({
  48. url: `/organizations/${organization.slug}/events/${project.slug}:${eventId}/`,
  49. body: {
  50. id: eventId,
  51. entries: [
  52. {
  53. type: EntryType.SPANS,
  54. data: [
  55. {
  56. span_id: spanId,
  57. description: 'SELECT users FROM my_table LIMIT 1;',
  58. },
  59. ],
  60. },
  61. ],
  62. },
  63. });
  64. render(
  65. <FullSpanDescription
  66. group={groupId}
  67. shortDescription={'SELECT users FRO*'}
  68. moduleName={ModuleName.DB}
  69. />,
  70. {organization}
  71. );
  72. await waitForElementToBeRemoved(() => screen.getByTestId('loading-indicator'));
  73. const queryCodeSnippet = await screen.findByText(
  74. /select users from my_table limit 1;/i
  75. );
  76. expect(queryCodeSnippet).toBeInTheDocument();
  77. expect(queryCodeSnippet).toHaveClass('language-sql');
  78. });
  79. it('uses the correct code formatting for MongoDB queries', async function () {
  80. MockApiClient.addMockResponse({
  81. url: `/organizations/${organization.slug}/events/`,
  82. body: {
  83. data: [
  84. {
  85. 'transaction.id': eventId,
  86. project: project.slug,
  87. span_id: spanId,
  88. },
  89. ],
  90. },
  91. });
  92. MockApiClient.addMockResponse({
  93. url: `/organizations/${organization.slug}/events/${project.slug}:${eventId}/`,
  94. body: {
  95. id: eventId,
  96. entries: [
  97. {
  98. type: EntryType.SPANS,
  99. data: [
  100. {
  101. span_id: spanId,
  102. description: `{"insert": "my_cool_collection😎", "a": {}}`,
  103. data: {'db.system': 'mongodb'},
  104. },
  105. ],
  106. },
  107. ],
  108. },
  109. });
  110. render(<FullSpanDescription group={groupId} moduleName={ModuleName.DB} />, {
  111. organization,
  112. });
  113. await waitForElementToBeRemoved(() => screen.getByTestId('loading-indicator'));
  114. const queryCodeSnippet = screen.getByText(
  115. /\{ "insert": "my_cool_collection😎", "a": \{\} \}/i
  116. );
  117. expect(queryCodeSnippet).toBeInTheDocument();
  118. expect(queryCodeSnippet).toHaveClass('language-json');
  119. });
  120. it('successfully handles truncated MongoDB queries', async function () {
  121. MockApiClient.addMockResponse({
  122. url: `/organizations/${organization.slug}/events/`,
  123. body: {
  124. data: [
  125. {
  126. 'transaction.id': eventId,
  127. project: project.slug,
  128. span_id: spanId,
  129. },
  130. ],
  131. },
  132. });
  133. MockApiClient.addMockResponse({
  134. url: `/organizations/${organization.slug}/events/${project.slug}:${eventId}/`,
  135. body: {
  136. id: eventId,
  137. entries: [
  138. {
  139. type: EntryType.SPANS,
  140. data: [
  141. {
  142. span_id: spanId,
  143. description: `{"insert": "my_cool_collection😎", "a": {}, "uh_oh":"the_query_is_truncated", "ohno*`,
  144. data: {'db.system': 'mongodb'},
  145. },
  146. ],
  147. },
  148. ],
  149. },
  150. });
  151. render(<FullSpanDescription group={groupId} moduleName={ModuleName.DB} />, {
  152. organization,
  153. });
  154. await waitForElementToBeRemoved(() => screen.getByTestId('loading-indicator'));
  155. // The last truncated entry will have a null value assigned and the JSON document is properly closed
  156. const queryCodeSnippet = screen.getByText(
  157. /\{ "insert": "my_cool_collection😎", "a": \{\}, "uh_oh": "the_query_is_truncated", "ohno\*": null \}/i
  158. );
  159. expect(queryCodeSnippet).toBeInTheDocument();
  160. expect(queryCodeSnippet).toHaveClass('language-json');
  161. });
  162. });