searchBar.spec.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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', 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. userEvent.type(screen.getByRole('textbox'), 'url:"fu"');
  37. expect(tagValuesMock).toHaveBeenLastCalledWith(
  38. expect.anything(),
  39. expect.objectContaining({
  40. query: expect.objectContaining({
  41. query: 'fu',
  42. }),
  43. })
  44. );
  45. expect(screen.getByTestId('smart-search-dropdown')).toBeInTheDocument();
  46. expect(screen.queryByRole('listitem')).not.toBeInTheDocument();
  47. });
  48. it('sets state when value has colon', 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. userEvent.type(screen.getByRole('textbox'), 'url:');
  58. expect(tagValuesMock).toHaveBeenCalled();
  59. });
  60. it('does not request values when tag is `timesSeen`', function () {
  61. const tagValuesMock = MockApiClient.addMockResponse({
  62. url: '/organizations/org-slug/tags/url/values/',
  63. method: 'GET',
  64. body: [],
  65. });
  66. render(<IssueListSearchBar {...defaultProps} />, {
  67. context: routerContext,
  68. });
  69. userEvent.type(screen.getByRole('textbox'), 'timesSeen:');
  70. expect(tagValuesMock).not.toHaveBeenCalled();
  71. });
  72. });
  73. describe('Recent Searches', function () {
  74. it('saves search query as a recent search', function () {
  75. const tagValuesMock = MockApiClient.addMockResponse({
  76. url: '/organizations/org-slug/tags/url/values/',
  77. method: 'GET',
  78. body: [],
  79. });
  80. const saveRecentSearch = MockApiClient.addMockResponse({
  81. url: '/organizations/org-slug/recent-searches/',
  82. method: 'POST',
  83. body: {},
  84. });
  85. const onSearch = jest.fn();
  86. render(<IssueListSearchBar {...defaultProps} onSearch={onSearch} />, {
  87. context: routerContext,
  88. });
  89. userEvent.type(screen.getByRole('textbox'), 'url:"fu"');
  90. expect(tagValuesMock).toHaveBeenLastCalledWith(
  91. expect.anything(),
  92. expect.objectContaining({
  93. query: expect.objectContaining({
  94. query: 'fu',
  95. }),
  96. })
  97. );
  98. expect(screen.getByTestId('smart-search-dropdown')).toBeInTheDocument();
  99. expect(screen.queryByRole('listitem')).not.toBeInTheDocument();
  100. userEvent.keyboard('{Enter}');
  101. expect(onSearch).toHaveBeenCalledWith('url:"fu"');
  102. expect(saveRecentSearch).toHaveBeenCalledWith(
  103. expect.anything(),
  104. expect.objectContaining({
  105. data: {
  106. query: 'url:"fu"',
  107. type: 0,
  108. },
  109. })
  110. );
  111. });
  112. it('queries for recent searches', function () {
  113. MockApiClient.addMockResponse({
  114. url: '/organizations/org-slug/tags/url/values/',
  115. method: 'GET',
  116. body: [],
  117. });
  118. render(<IssueListSearchBar {...defaultProps} />, {context: routerContext});
  119. userEvent.type(screen.getByRole('textbox'), 'is:');
  120. expect(recentSearchMock).toHaveBeenCalledWith(
  121. expect.anything(),
  122. expect.objectContaining({
  123. query: {
  124. query: 'is:',
  125. limit: 3,
  126. type: 0,
  127. },
  128. })
  129. );
  130. });
  131. // Flaky due to timeouts, see https://github.com/getsentry/sentry/issues/42898
  132. // eslint-disable-next-line jest/no-disabled-tests
  133. it.skip('cycles through keyboard navigation for selection', async function () {
  134. MockApiClient.addMockResponse({
  135. url: '/organizations/org-slug/tags/device.orientation/values/',
  136. method: 'GET',
  137. body: [],
  138. });
  139. render(<IssueListSearchBar {...defaultProps} />, {context: routerContext});
  140. const textarea = screen.getByRole('textbox');
  141. // Keyboard navigate to first item and select
  142. userEvent.type(textarea, 't');
  143. await waitFor(() =>
  144. expect(screen.getAllByTestId('search-autocomplete-item')[0]).toBeInTheDocument()
  145. );
  146. userEvent.keyboard('{ArrowDown}{Tab}');
  147. expect(textarea).not.toHaveValue('t');
  148. const firstItemValue = textarea.textContent;
  149. // Keyboard navigate to second item and select
  150. userEvent.keyboard('{selectall}{backspace}t');
  151. await waitFor(() =>
  152. expect(screen.getAllByTestId('search-autocomplete-item')[0]).toBeInTheDocument()
  153. );
  154. userEvent.keyboard('{ArrowDown}{ArrowDown}{Tab}');
  155. expect(textarea).not.toHaveValue(firstItemValue);
  156. // Keyboard navigate to second item, then back to first item and select
  157. userEvent.keyboard('{selectall}{backspace}t');
  158. await waitFor(() =>
  159. expect(screen.getAllByTestId('search-autocomplete-item')[0]).toBeInTheDocument()
  160. );
  161. userEvent.keyboard('{ArrowDown}{ArrowDown}{ArrowUp}{Tab}');
  162. expect(textarea).toHaveValue(firstItemValue);
  163. });
  164. });
  165. });