searchBar.spec.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import {TagsFixture} from 'sentry-fixture/tags';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  4. import TagStore from 'sentry/stores/tagStore';
  5. import {IsFieldValues} from 'sentry/utils/fields';
  6. import IssueListSearchBar from 'sentry/views/issueList/searchBar';
  7. describe('IssueListSearchBar', function () {
  8. let recentSearchMock;
  9. let defaultProps;
  10. const {router, organization} = initializeOrg();
  11. beforeEach(function () {
  12. TagStore.reset();
  13. TagStore.loadTagsSuccess(TagsFixture());
  14. defaultProps = {
  15. organization,
  16. query: '',
  17. onSearch: jest.fn(),
  18. };
  19. recentSearchMock = MockApiClient.addMockResponse({
  20. url: '/organizations/org-slug/recent-searches/',
  21. method: 'GET',
  22. body: [],
  23. });
  24. });
  25. afterEach(function () {
  26. MockApiClient.clearMockResponses();
  27. });
  28. describe('updateAutoCompleteItems()', function () {
  29. it('sets state with complete tag', async function () {
  30. const tagValuesMock = MockApiClient.addMockResponse({
  31. url: '/organizations/org-slug/tags/url/values/',
  32. method: 'GET',
  33. body: [],
  34. });
  35. render(<IssueListSearchBar {...defaultProps} />, {
  36. router,
  37. });
  38. await userEvent.click(screen.getByRole('textbox'));
  39. await userEvent.paste('url:"fu"');
  40. expect(tagValuesMock).toHaveBeenLastCalledWith(
  41. expect.anything(),
  42. expect.objectContaining({
  43. query: expect.objectContaining({
  44. query: 'fu',
  45. }),
  46. })
  47. );
  48. expect(screen.getByTestId('smart-search-dropdown')).toBeInTheDocument();
  49. });
  50. it('sets state when value has colon', async function () {
  51. const tagValuesMock = MockApiClient.addMockResponse({
  52. url: '/organizations/org-slug/tags/url/values/',
  53. method: 'GET',
  54. body: [],
  55. });
  56. render(<IssueListSearchBar {...defaultProps} />, {
  57. router,
  58. });
  59. await userEvent.click(screen.getByRole('textbox'));
  60. await userEvent.paste('url:', {delay: null});
  61. expect(tagValuesMock).toHaveBeenCalled();
  62. });
  63. it('does not request values when tag is `timesSeen`', async function () {
  64. const tagValuesMock = MockApiClient.addMockResponse({
  65. url: '/organizations/org-slug/tags/url/values/',
  66. method: 'GET',
  67. body: [],
  68. });
  69. render(<IssueListSearchBar {...defaultProps} />, {
  70. router,
  71. });
  72. await userEvent.click(screen.getByRole('textbox'));
  73. await userEvent.paste('timesSeen:', {delay: null});
  74. expect(tagValuesMock).not.toHaveBeenCalled();
  75. });
  76. });
  77. describe('Recent Searches', function () {
  78. it('saves search query as a recent search', async function () {
  79. const tagValuesMock = MockApiClient.addMockResponse({
  80. url: '/organizations/org-slug/tags/url/values/',
  81. method: 'GET',
  82. body: [],
  83. });
  84. const saveRecentSearch = MockApiClient.addMockResponse({
  85. url: '/organizations/org-slug/recent-searches/',
  86. method: 'POST',
  87. body: {},
  88. });
  89. const onSearch = jest.fn();
  90. render(<IssueListSearchBar {...defaultProps} onSearch={onSearch} />, {
  91. router,
  92. });
  93. await userEvent.click(screen.getByRole('textbox'));
  94. await userEvent.paste('url:"fu"');
  95. expect(tagValuesMock).toHaveBeenLastCalledWith(
  96. expect.anything(),
  97. expect.objectContaining({
  98. query: expect.objectContaining({
  99. query: 'fu',
  100. }),
  101. })
  102. );
  103. expect(screen.getByTestId('smart-search-dropdown')).toBeInTheDocument();
  104. await userEvent.keyboard('{Enter}');
  105. expect(onSearch).toHaveBeenCalledWith('url:"fu"');
  106. expect(saveRecentSearch).toHaveBeenCalledWith(
  107. expect.anything(),
  108. expect.objectContaining({
  109. data: {
  110. query: 'url:"fu"',
  111. type: 0,
  112. },
  113. })
  114. );
  115. });
  116. it('queries for recent searches', async function () {
  117. MockApiClient.addMockResponse({
  118. url: '/organizations/org-slug/tags/url/values/',
  119. method: 'GET',
  120. body: [],
  121. });
  122. render(<IssueListSearchBar {...defaultProps} />, {router});
  123. await userEvent.click(screen.getByRole('textbox'));
  124. await userEvent.paste('is:', {delay: null});
  125. expect(recentSearchMock).toHaveBeenCalledWith(
  126. expect.anything(),
  127. expect.objectContaining({
  128. query: {
  129. query: 'is:',
  130. limit: 3,
  131. type: 0,
  132. },
  133. })
  134. );
  135. });
  136. });
  137. describe('Tags and Fields', function () {
  138. const {router: routerWithFlag, organization: orgWithFlag} = initializeOrg();
  139. orgWithFlag.features = ['issue-stream-search-query-builder'];
  140. const newDefaultProps = {
  141. organization: orgWithFlag,
  142. query: '',
  143. statsPeriod: '7d',
  144. onSearch: jest.fn(),
  145. };
  146. it('displays the correct options for the is tag', async function () {
  147. MockApiClient.addMockResponse({
  148. url: '/organizations/org-slug/tags/',
  149. body: [],
  150. });
  151. render(<IssueListSearchBar {...newDefaultProps} />, {
  152. router: routerWithFlag,
  153. });
  154. await userEvent.click(screen.getByRole('combobox', {name: 'Add a search term'}));
  155. await userEvent.paste('is:', {delay: null});
  156. await userEvent.click(
  157. await screen.findByRole('button', {name: 'Edit value for filter: is'})
  158. );
  159. Object.values(IsFieldValues).forEach(value => {
  160. expect(screen.getByRole('option', {name: value})).toBeInTheDocument();
  161. });
  162. });
  163. it('displays the correct options under Event Tags', async function () {
  164. MockApiClient.addMockResponse({
  165. url: '/organizations/org-slug/tags/',
  166. body: [{key: 'someTag', name: 'Some Tag'}],
  167. });
  168. defaultProps.organization.features = ['issue-stream-search-query-builder'];
  169. render(<IssueListSearchBar {...newDefaultProps} />, {
  170. router: routerWithFlag,
  171. });
  172. await userEvent.click(screen.getByRole('combobox', {name: 'Add a search term'}));
  173. await userEvent.click(screen.getByRole('button', {name: 'Event Tags'}));
  174. expect(await screen.findByRole('option', {name: 'someTag'})).toBeInTheDocument();
  175. });
  176. it('displays tags in the has filter', async function () {
  177. MockApiClient.addMockResponse({
  178. url: '/organizations/org-slug/tags/',
  179. body: [{key: 'someTag', name: 'Some Tag'}],
  180. });
  181. defaultProps.organization.features = ['issue-stream-search-query-builder'];
  182. render(<IssueListSearchBar {...newDefaultProps} />, {
  183. router: routerWithFlag,
  184. });
  185. await userEvent.click(screen.getByRole('combobox', {name: 'Add a search term'}));
  186. await userEvent.paste('has:', {delay: null});
  187. await userEvent.click(
  188. await screen.findByRole('button', {name: 'Edit value for filter: has'})
  189. );
  190. expect(await screen.findByRole('option', {name: 'someTag'})).toBeInTheDocument();
  191. });
  192. });
  193. });