eventSamplesTable.spec.tsx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. import {LocationFixture} from 'sentry-fixture/locationFixture';
  2. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  3. import type {NewQuery} from 'sentry/types/organization';
  4. import {browserHistory} from 'sentry/utils/browserHistory';
  5. import EventView from 'sentry/utils/discover/eventView';
  6. import {EventSamplesTable} from 'sentry/views/insights/mobile/screenload/components/tables/eventSamplesTable';
  7. describe('EventSamplesTable', function () {
  8. let mockLocation, mockQuery: NewQuery, mockEventView;
  9. beforeEach(function () {
  10. mockLocation = LocationFixture({
  11. query: {
  12. statsPeriod: '99d',
  13. },
  14. });
  15. mockQuery = {
  16. name: '',
  17. fields: ['transaction.id'],
  18. query: '',
  19. version: 2,
  20. };
  21. mockEventView = EventView.fromNewQueryWithLocation(mockQuery, mockLocation);
  22. });
  23. it('uses a column name map to render column names', function () {
  24. mockQuery = {
  25. name: '',
  26. fields: ['rawField'],
  27. query: '',
  28. version: 2,
  29. };
  30. mockEventView = EventView.fromNewQueryWithLocation(mockQuery, mockLocation);
  31. render(
  32. <EventSamplesTable
  33. columnNameMap={{
  34. rawField: 'Readable Column Name',
  35. }}
  36. cursorName=""
  37. eventIdKey="transaction.id"
  38. eventView={mockEventView}
  39. isLoading={false}
  40. profileIdKey="profile.id"
  41. sort={{
  42. field: '',
  43. kind: 'desc',
  44. }}
  45. sortKey=""
  46. />
  47. );
  48. expect(screen.getByText('Readable Column Name')).toBeInTheDocument();
  49. expect(screen.queryByText('rawField')).not.toBeInTheDocument();
  50. });
  51. it('uses the event ID key to get the event ID from the data payload', function () {
  52. mockQuery = {
  53. name: '',
  54. fields: ['transaction.id'],
  55. query: '',
  56. version: 2,
  57. };
  58. mockEventView = EventView.fromNewQueryWithLocation(mockQuery, mockLocation);
  59. render(
  60. <EventSamplesTable
  61. eventIdKey="transaction.id"
  62. columnNameMap={{'transaction.id': 'Event ID'}}
  63. cursorName=""
  64. eventView={mockEventView}
  65. isLoading={false}
  66. profileIdKey="profile.id"
  67. sort={{
  68. field: '',
  69. kind: 'desc',
  70. }}
  71. sortKey=""
  72. data={{data: [{id: '1', 'transaction.id': 'abc'}], meta: {}}}
  73. />
  74. );
  75. // Test only one column to isolate event ID
  76. expect(screen.getAllByRole('columnheader')).toHaveLength(1);
  77. expect(screen.getByRole('columnheader', {name: 'Event ID'})).toBeInTheDocument();
  78. expect(screen.getByText('abc')).toBeInTheDocument();
  79. expect(screen.queryByText('1')).not.toBeInTheDocument();
  80. });
  81. it('uses the profile ID key to get the profile ID from the data payload and display an icon button', async function () {
  82. mockQuery = {
  83. name: '',
  84. fields: ['profile.id', 'project.name'], // Project name is required to form the profile target
  85. query: '',
  86. version: 2,
  87. };
  88. mockEventView = EventView.fromNewQueryWithLocation(mockQuery, mockLocation);
  89. render(
  90. <EventSamplesTable
  91. profileIdKey="profile.id"
  92. columnNameMap={{'profile.id': 'Profile'}}
  93. eventIdKey="transaction.id"
  94. cursorName=""
  95. eventView={mockEventView}
  96. isLoading={false}
  97. sort={{
  98. field: '',
  99. kind: 'desc',
  100. }}
  101. sortKey=""
  102. data={{
  103. data: [{id: '1', 'profile.id': 'abc', 'project.name': 'project'}],
  104. meta: {fields: {'profile.id': 'string', 'project.name': 'string'}},
  105. }}
  106. />
  107. );
  108. // Test only one column to isolate profile column
  109. expect(screen.getAllByRole('columnheader')).toHaveLength(1);
  110. expect(screen.getByRole('columnheader', {name: 'Profile'})).toBeInTheDocument();
  111. expect(await screen.findByRole('button', {name: 'View Profile'})).toBeInTheDocument();
  112. });
  113. it('updates URL params when device class selector is changed', async function () {
  114. mockQuery = {
  115. name: '',
  116. fields: ['transaction.id'],
  117. query: '',
  118. version: 2,
  119. };
  120. mockEventView = EventView.fromNewQueryWithLocation(mockQuery, mockLocation);
  121. render(
  122. <EventSamplesTable
  123. showDeviceClassSelector
  124. eventIdKey="transaction.id"
  125. columnNameMap={{'transaction.id': 'Event ID'}}
  126. cursorName=""
  127. eventView={mockEventView}
  128. isLoading={false}
  129. profileIdKey="profile.id"
  130. sort={{
  131. field: '',
  132. kind: 'desc',
  133. }}
  134. sortKey=""
  135. data={{data: [{id: '1', 'transaction.id': 'abc'}], meta: {}}}
  136. />
  137. );
  138. expect(screen.getByRole('button', {name: /device class all/i})).toBeInTheDocument();
  139. await userEvent.click(screen.getByRole('button', {name: /device class all/i}));
  140. await userEvent.click(screen.getByText('Medium'));
  141. expect(browserHistory.push).toHaveBeenCalledWith(
  142. expect.objectContaining({
  143. pathname: '/mock-pathname/',
  144. query: expect.objectContaining({
  145. 'device.class': 'medium',
  146. }),
  147. })
  148. );
  149. });
  150. it('updates URL params when the table is paginated', async function () {
  151. const pageLinks =
  152. '<https://sentry.io/fake/previous>; rel="previous"; results="false"; cursor="0:0:1", ' +
  153. '<https://sentry.io/fake/next>; rel="next"; results="true"; cursor="0:20:0"';
  154. render(
  155. <EventSamplesTable
  156. showDeviceClassSelector
  157. eventIdKey="transaction.id"
  158. columnNameMap={{'transaction.id': 'Event ID'}}
  159. cursorName="customCursorName"
  160. eventView={mockEventView}
  161. isLoading={false}
  162. profileIdKey="profile.id"
  163. sort={{
  164. field: '',
  165. kind: 'desc',
  166. }}
  167. sortKey=""
  168. data={{data: [{id: '1', 'transaction.id': 'abc'}], meta: {}}}
  169. pageLinks={pageLinks}
  170. />
  171. );
  172. expect(screen.getByRole('button', {name: 'Next'})).toBeInTheDocument();
  173. await userEvent.click(screen.getByRole('button', {name: 'Next'}));
  174. expect(browserHistory.push).toHaveBeenCalledWith(
  175. expect.objectContaining({
  176. pathname: '/mock-pathname/',
  177. query: expect.objectContaining({
  178. customCursorName: '0:20:0',
  179. }),
  180. })
  181. );
  182. });
  183. it('uses a custom sort key for sortable headers', async function () {
  184. mockQuery = {
  185. name: '',
  186. fields: ['transaction.id', 'duration'],
  187. query: '',
  188. version: 2,
  189. };
  190. mockEventView = EventView.fromNewQueryWithLocation(mockQuery, mockLocation);
  191. render(
  192. <EventSamplesTable
  193. showDeviceClassSelector
  194. eventIdKey="transaction.id"
  195. columnNameMap={{'transaction.id': 'Event ID', duration: 'Duration'}}
  196. cursorName="customCursorName"
  197. eventView={mockEventView}
  198. isLoading={false}
  199. profileIdKey="profile.id"
  200. sort={{
  201. field: 'transaction.id',
  202. kind: 'desc',
  203. }}
  204. sortKey="customSortKey"
  205. data={{data: [{id: '1', 'transaction.id': 'abc', duration: 'def'}], meta: {}}}
  206. />
  207. );
  208. // Ascending sort in transaction ID because the default is descending
  209. expect(await screen.findByRole('link', {name: 'Event ID'})).toHaveAttribute(
  210. 'href',
  211. '/mock-pathname/?customSortKey=transaction.id'
  212. );
  213. expect(screen.getByRole('link', {name: 'Duration'})).toHaveAttribute(
  214. 'href',
  215. '/mock-pathname/?customSortKey=-duration'
  216. );
  217. });
  218. it('only displays data for the columns defined in the name map', async function () {
  219. mockQuery = {
  220. name: '',
  221. fields: ['transaction.id', 'duration'],
  222. query: '',
  223. version: 2,
  224. };
  225. mockEventView = EventView.fromNewQueryWithLocation(mockQuery, mockLocation);
  226. render(
  227. <EventSamplesTable
  228. eventIdKey="transaction.id"
  229. columnNameMap={{duration: 'Duration'}}
  230. cursorName="customCursorName"
  231. eventView={mockEventView}
  232. isLoading={false}
  233. profileIdKey="profile.id"
  234. sort={{
  235. field: 'transaction.id',
  236. kind: 'desc',
  237. }}
  238. sortKey="customSortKey"
  239. data={{data: [{id: '1', 'transaction.id': 'abc', duration: 'def'}], meta: {}}}
  240. />
  241. );
  242. // Although ID is queried for, because it's not defined in the map
  243. // it isn't rendered
  244. expect(
  245. await screen.findByRole('columnheader', {name: 'Duration'})
  246. ).toBeInTheDocument();
  247. expect(screen.getAllByRole('columnheader')).toHaveLength(1);
  248. });
  249. });