searchBar.spec.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  3. import TagStore from 'sentry/stores/tagStore';
  4. import IssueListSearchBar from 'sentry/views/issueList/searchBar';
  5. describe('IssueListSearchBar', function () {
  6. let recentSearchMock;
  7. let defaultProps;
  8. const {routerContext, organization} = initializeOrg();
  9. beforeEach(function () {
  10. TagStore.reset();
  11. TagStore.loadTagsSuccess(TestStubs.Tags());
  12. defaultProps = {
  13. organization,
  14. query: '',
  15. onSearch: jest.fn(),
  16. };
  17. recentSearchMock = MockApiClient.addMockResponse({
  18. url: '/organizations/org-slug/recent-searches/',
  19. method: 'GET',
  20. body: [],
  21. });
  22. });
  23. afterEach(function () {
  24. MockApiClient.clearMockResponses();
  25. });
  26. describe('updateAutoCompleteItems()', function () {
  27. it('sets state with complete tag', async function () {
  28. const tagValuesMock = MockApiClient.addMockResponse({
  29. url: '/organizations/org-slug/tags/url/values/',
  30. method: 'GET',
  31. body: [],
  32. });
  33. render(<IssueListSearchBar {...defaultProps} />, {
  34. context: routerContext,
  35. });
  36. await userEvent.click(screen.getByRole('textbox'));
  37. await userEvent.paste('url:"fu"');
  38. expect(tagValuesMock).toHaveBeenLastCalledWith(
  39. expect.anything(),
  40. expect.objectContaining({
  41. query: expect.objectContaining({
  42. query: 'fu',
  43. }),
  44. })
  45. );
  46. expect(screen.getByTestId('smart-search-dropdown')).toBeInTheDocument();
  47. });
  48. it('sets state when value has colon', async function () {
  49. const tagValuesMock = MockApiClient.addMockResponse({
  50. url: '/organizations/org-slug/tags/url/values/',
  51. method: 'GET',
  52. body: [],
  53. });
  54. render(<IssueListSearchBar {...defaultProps} />, {
  55. context: routerContext,
  56. });
  57. await userEvent.click(screen.getByRole('textbox'));
  58. await userEvent.paste('url:', {delay: null});
  59. expect(tagValuesMock).toHaveBeenCalled();
  60. });
  61. it('does not request values when tag is `timesSeen`', async function () {
  62. const tagValuesMock = MockApiClient.addMockResponse({
  63. url: '/organizations/org-slug/tags/url/values/',
  64. method: 'GET',
  65. body: [],
  66. });
  67. render(<IssueListSearchBar {...defaultProps} />, {
  68. context: routerContext,
  69. });
  70. await userEvent.click(screen.getByRole('textbox'));
  71. await userEvent.paste('timesSeen:', {delay: null});
  72. expect(tagValuesMock).not.toHaveBeenCalled();
  73. });
  74. });
  75. describe('Recent Searches', function () {
  76. it('saves search query as a recent search', async function () {
  77. const tagValuesMock = MockApiClient.addMockResponse({
  78. url: '/organizations/org-slug/tags/url/values/',
  79. method: 'GET',
  80. body: [],
  81. });
  82. const saveRecentSearch = MockApiClient.addMockResponse({
  83. url: '/organizations/org-slug/recent-searches/',
  84. method: 'POST',
  85. body: {},
  86. });
  87. const onSearch = jest.fn();
  88. render(<IssueListSearchBar {...defaultProps} onSearch={onSearch} />, {
  89. context: routerContext,
  90. });
  91. await userEvent.click(screen.getByRole('textbox'));
  92. await userEvent.paste('url:"fu"');
  93. expect(tagValuesMock).toHaveBeenLastCalledWith(
  94. expect.anything(),
  95. expect.objectContaining({
  96. query: expect.objectContaining({
  97. query: 'fu',
  98. }),
  99. })
  100. );
  101. expect(screen.getByTestId('smart-search-dropdown')).toBeInTheDocument();
  102. await userEvent.keyboard('{Enter}');
  103. expect(onSearch).toHaveBeenCalledWith('url:"fu"');
  104. expect(saveRecentSearch).toHaveBeenCalledWith(
  105. expect.anything(),
  106. expect.objectContaining({
  107. data: {
  108. query: 'url:"fu"',
  109. type: 0,
  110. },
  111. })
  112. );
  113. });
  114. it('queries for recent searches', async function () {
  115. MockApiClient.addMockResponse({
  116. url: '/organizations/org-slug/tags/url/values/',
  117. method: 'GET',
  118. body: [],
  119. });
  120. render(<IssueListSearchBar {...defaultProps} />, {context: routerContext});
  121. await userEvent.click(screen.getByRole('textbox'));
  122. await userEvent.paste('is:', {delay: null});
  123. expect(recentSearchMock).toHaveBeenCalledWith(
  124. expect.anything(),
  125. expect.objectContaining({
  126. query: {
  127. query: 'is:',
  128. limit: 3,
  129. type: 0,
  130. },
  131. })
  132. );
  133. });
  134. // Flaky due to timeouts, see https://github.com/getsentry/sentry/issues/42898
  135. // eslint-disable-next-line jest/no-disabled-tests
  136. it.skip('cycles through keyboard navigation for selection', async function () {
  137. MockApiClient.addMockResponse({
  138. url: '/organizations/org-slug/tags/device.orientation/values/',
  139. method: 'GET',
  140. body: [],
  141. });
  142. render(<IssueListSearchBar {...defaultProps} />, {context: routerContext});
  143. const textarea = screen.getByRole('textbox');
  144. // Keyboard navigate to first item and select
  145. await userEvent.type(textarea, 't');
  146. await waitFor(() =>
  147. expect(screen.getAllByTestId('search-autocomplete-item')[0]).toBeInTheDocument()
  148. );
  149. await userEvent.keyboard('{ArrowDown}{Tab}');
  150. expect(textarea).not.toHaveValue('t');
  151. const firstItemValue = textarea.textContent;
  152. // Keyboard navigate to second item and select
  153. await userEvent.keyboard('{selectall}{backspace}t');
  154. await waitFor(() =>
  155. expect(screen.getAllByTestId('search-autocomplete-item')[0]).toBeInTheDocument()
  156. );
  157. await userEvent.keyboard('{ArrowDown}{ArrowDown}{Tab}');
  158. expect(textarea).not.toHaveValue(firstItemValue);
  159. // Keyboard navigate to second item, then back to first item and select
  160. await userEvent.keyboard('{selectall}{backspace}t');
  161. await waitFor(() =>
  162. expect(screen.getAllByTestId('search-autocomplete-item')[0]).toBeInTheDocument()
  163. );
  164. await userEvent.keyboard('{ArrowDown}{ArrowDown}{ArrowUp}{Tab}');
  165. expect(textarea).toHaveValue(firstItemValue);
  166. });
  167. });
  168. });