savedSearchesStore.spec.jsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import {
  2. deleteSavedSearch,
  3. fetchSavedSearches,
  4. pinSearch,
  5. unpinSearch,
  6. } from 'sentry/actionCreators/savedSearches';
  7. import {Client} from 'sentry/api';
  8. import SavedSearchesStore from 'sentry/stores/savedSearchesStore';
  9. import {SavedSearchType} from 'sentry/types';
  10. describe('SavedSearchesStore', function () {
  11. let api;
  12. beforeAll(async function () {
  13. api = new Client();
  14. await SavedSearchesStore.reset();
  15. });
  16. beforeEach(function () {
  17. Client.addMockResponse({
  18. url: '/organizations/org-1/searches/',
  19. body: TestStubs.Searches(),
  20. });
  21. Client.addMockResponse({
  22. url: '/organizations/org-1/pinned-searches/',
  23. method: 'PUT',
  24. body: {},
  25. });
  26. Client.addMockResponse({
  27. url: '/organizations/org-1/pinned-searches/',
  28. method: 'DELETE',
  29. });
  30. });
  31. afterEach(async function () {
  32. Client.clearMockResponses();
  33. SavedSearchesStore.reset();
  34. await tick();
  35. });
  36. it('get', function () {
  37. expect(SavedSearchesStore.get()).toEqual({
  38. hasError: false,
  39. isLoading: true,
  40. savedSearches: [],
  41. });
  42. });
  43. it('fetching saved searches updates store', async function () {
  44. await fetchSavedSearches(api, 'org-1', {});
  45. await tick();
  46. expect(SavedSearchesStore.get().savedSearches).toHaveLength(2);
  47. expect(SavedSearchesStore.get().isLoading).toBe(false);
  48. });
  49. it('failed fetches do not corrupt store', async function () {
  50. Client.addMockResponse({
  51. url: '/organizations/org-1/searches/',
  52. body: '',
  53. });
  54. await fetchSavedSearches(api, 'org-1', {});
  55. await tick();
  56. expect(SavedSearchesStore.get().savedSearches).toHaveLength(0);
  57. expect(SavedSearchesStore.get().isLoading).toBe(false);
  58. });
  59. it('creates a new pin search', async function () {
  60. await fetchSavedSearches(api, 'org-1', {});
  61. await tick();
  62. Client.addMockResponse({
  63. url: '/organizations/org-1/pinned-searches/',
  64. method: 'PUT',
  65. body: {
  66. id: '123',
  67. query: 'level:info',
  68. sort: 'freq',
  69. isPinned: true,
  70. },
  71. });
  72. pinSearch(api, 'org-1', 0, 'level:info', 'freq');
  73. await tick();
  74. await tick();
  75. expect(SavedSearchesStore.get().savedSearches).toHaveLength(3);
  76. expect(SavedSearchesStore.get().savedSearches[0]).toEqual(
  77. expect.objectContaining({
  78. id: '123',
  79. isPinned: true,
  80. type: SavedSearchType.ISSUE,
  81. query: 'level:info',
  82. name: 'My Pinned Search',
  83. sort: 'freq',
  84. })
  85. );
  86. });
  87. it('changes pinned search from a custom search to an existing search', async function () {
  88. const searches = TestStubs.Searches();
  89. Client.addMockResponse({
  90. url: '/organizations/org-1/searches/',
  91. body: [
  92. {
  93. id: null,
  94. isPinned: true,
  95. type: SavedSearchType.ISSUE,
  96. query: 'assigned:me',
  97. sort: 'date',
  98. },
  99. ...searches,
  100. ],
  101. });
  102. Client.addMockResponse({
  103. url: '/organizations/org-1/pinned-searches/',
  104. method: 'PUT',
  105. body: {
  106. id: '1',
  107. isGlobal: true,
  108. isPinned: true,
  109. query: 'is:unresolved',
  110. sort: 'date',
  111. name: 'Unresolved Issues',
  112. type: SavedSearchType.ISSUE,
  113. },
  114. });
  115. await fetchSavedSearches(api, 'org-1', {});
  116. await tick();
  117. pinSearch(api, 'org-1', 0, searches[1].query, 'date');
  118. await tick();
  119. await tick();
  120. // Order should remain the same
  121. expect(SavedSearchesStore.get().savedSearches[1]).toEqual(
  122. expect.objectContaining({
  123. id: '1',
  124. isGlobal: true,
  125. isPinned: true,
  126. type: SavedSearchType.ISSUE,
  127. name: 'Unresolved Issues',
  128. query: 'is:unresolved',
  129. sort: 'date',
  130. })
  131. );
  132. // Saved custom search should be removed
  133. expect(SavedSearchesStore.get().savedSearches).toHaveLength(2);
  134. });
  135. it('changes pinned search from an existing search to another existing search', async function () {
  136. const searches = TestStubs.Searches();
  137. Client.addMockResponse({
  138. url: '/organizations/org-1/searches/',
  139. body: [{...searches[0], isPinned: true}, searches[1]],
  140. });
  141. Client.addMockResponse({
  142. url: '/organizations/org-1/pinned-searches/',
  143. method: 'PUT',
  144. body: {
  145. id: '1',
  146. isGlobal: true,
  147. isPinned: true,
  148. query: 'is:unresolved',
  149. sort: 'date',
  150. name: 'Unresolved Issues',
  151. type: SavedSearchType.ISSUE,
  152. },
  153. });
  154. await fetchSavedSearches(api, 'org-1', {});
  155. await tick();
  156. pinSearch(api, 'org-1', 0, searches[1].query, 'date');
  157. await tick();
  158. await tick();
  159. expect(SavedSearchesStore.get().savedSearches).toHaveLength(2);
  160. expect(SavedSearchesStore.get().savedSearches[0]).toEqual(
  161. expect.objectContaining({
  162. id: '2',
  163. isPinned: false,
  164. type: SavedSearchType.ISSUE,
  165. name: 'Needs Triage',
  166. query: 'is:unresolved is:unassigned',
  167. sort: 'date',
  168. })
  169. );
  170. expect(SavedSearchesStore.get().savedSearches[1]).toEqual(
  171. expect.objectContaining({
  172. id: '1',
  173. isGlobal: true,
  174. isPinned: true,
  175. type: SavedSearchType.ISSUE,
  176. name: 'Unresolved Issues',
  177. query: 'is:unresolved',
  178. sort: 'date',
  179. })
  180. );
  181. });
  182. it('unpins a user custom search', async function () {
  183. const searches = TestStubs.Searches();
  184. Client.addMockResponse({
  185. url: '/organizations/org-1/searches/',
  186. body: [
  187. {
  188. id: null,
  189. isPinned: true,
  190. type: SavedSearchType.ISSUE,
  191. query: 'assigned:me',
  192. sort: 'date',
  193. },
  194. ...searches,
  195. ],
  196. });
  197. await fetchSavedSearches(api, 'org-1', {});
  198. await tick();
  199. unpinSearch(api, 'org-1', 0, searches[0]);
  200. await tick();
  201. await tick();
  202. // Saved custom search should be removed
  203. expect(SavedSearchesStore.get().savedSearches).toHaveLength(2);
  204. expect(SavedSearchesStore.get().savedSearches[0]).toEqual(
  205. expect.objectContaining({
  206. id: '2',
  207. isPinned: false,
  208. type: SavedSearchType.ISSUE,
  209. name: 'Needs Triage',
  210. query: 'is:unresolved is:unassigned',
  211. sort: 'date',
  212. })
  213. );
  214. expect(SavedSearchesStore.get().savedSearches[1]).toEqual(
  215. expect.objectContaining({
  216. id: '1',
  217. isPinned: false,
  218. type: SavedSearchType.ISSUE,
  219. name: 'Unresolved Issues',
  220. query: 'is:unresolved',
  221. sort: 'date',
  222. })
  223. );
  224. });
  225. it('removes deleted saved searches', async function () {
  226. await fetchSavedSearches(api, 'org-1', {});
  227. await tick();
  228. const searches = SavedSearchesStore.get().savedSearches;
  229. Client.addMockResponse({
  230. url: `/organizations/org-1/searches/${searches[0].id}/`,
  231. method: 'DELETE',
  232. body: {},
  233. });
  234. await deleteSavedSearch(api, 'org-1', searches[0]);
  235. await tick();
  236. const newSearches = SavedSearchesStore.get().savedSearches;
  237. expect(newSearches.length).toBeLessThan(searches.length);
  238. expect(newSearches[0].id).not.toBe(searches[0].id);
  239. });
  240. });