api.spec.jsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import $ from 'jquery';
  2. import GroupActions from 'app/actions/groupActions';
  3. import {Client, paramsToQueryArgs, Request} from 'app/api';
  4. import {PROJECT_MOVED} from 'app/constants/apiErrorCodes';
  5. jest.unmock('app/api');
  6. describe('api', function () {
  7. let api;
  8. beforeEach(function () {
  9. api = new Client();
  10. });
  11. describe('paramsToQueryArgs()', function () {
  12. it('should convert itemIds properties to id array', function () {
  13. expect(
  14. paramsToQueryArgs({
  15. itemIds: [1, 2, 3],
  16. query: 'is:unresolved', // itemIds takes precedence
  17. })
  18. ).toEqual({id: [1, 2, 3]});
  19. });
  20. it('should extract query property if no itemIds', function () {
  21. expect(
  22. paramsToQueryArgs({
  23. query: 'is:unresolved',
  24. foo: 'bar',
  25. })
  26. ).toEqual({query: 'is:unresolved'});
  27. });
  28. it('should convert params w/o itemIds or query to empty object', function () {
  29. expect(
  30. paramsToQueryArgs({
  31. foo: 'bar',
  32. bar: 'baz', // paramsToQueryArgs ignores these
  33. })
  34. ).toEqual({});
  35. });
  36. it('should keep environment when query is provided', function () {
  37. expect(
  38. paramsToQueryArgs({
  39. query: 'is:unresolved',
  40. environment: 'production',
  41. })
  42. ).toEqual({query: 'is:unresolved', environment: 'production'});
  43. });
  44. it('should exclude environment when it is null/undefined', function () {
  45. expect(
  46. paramsToQueryArgs({
  47. query: 'is:unresolved',
  48. environment: null,
  49. })
  50. ).toEqual({query: 'is:unresolved'});
  51. });
  52. it('should handle non-empty projects', function () {
  53. expect(
  54. paramsToQueryArgs({
  55. itemIds: [1, 2, 3],
  56. project: [1],
  57. })
  58. ).toEqual({id: [1, 2, 3], project: [1]});
  59. expect(
  60. paramsToQueryArgs({
  61. itemIds: [1, 2, 3],
  62. project: [],
  63. })
  64. ).toEqual({id: [1, 2, 3]});
  65. expect(
  66. paramsToQueryArgs({
  67. itemIds: [1, 2, 3],
  68. project: null,
  69. })
  70. ).toEqual({id: [1, 2, 3]});
  71. });
  72. });
  73. describe('Client', function () {
  74. beforeEach(function () {
  75. jest.spyOn($, 'ajax');
  76. });
  77. describe('cancel()', function () {
  78. it('should abort any open XHR requests', function () {
  79. const req1 = new Request({
  80. abort: jest.fn(),
  81. });
  82. const req2 = new Request({
  83. abort: jest.fn(),
  84. });
  85. api.activeRequests = {
  86. 1: req1,
  87. 2: req2,
  88. };
  89. api.clear();
  90. expect(req1.xhr.abort).toHaveBeenCalledTimes(1);
  91. expect(req2.xhr.abort).toHaveBeenCalledTimes(1);
  92. });
  93. });
  94. });
  95. it('does not call success callback if 302 was returned because of a project slug change', function () {
  96. const successCb = jest.fn();
  97. api.activeRequests = {id: {alive: true}};
  98. api.wrapCallback(
  99. 'id',
  100. successCb
  101. )({
  102. responseJSON: {
  103. detail: {
  104. code: PROJECT_MOVED,
  105. message: '...',
  106. extra: {
  107. slug: 'new-slug',
  108. },
  109. },
  110. },
  111. });
  112. expect(successCb).not.toHaveBeenCalled();
  113. });
  114. it('handles error callback', function () {
  115. jest.spyOn(api, 'wrapCallback').mockImplementation((_id, func) => func);
  116. const errorCb = jest.fn();
  117. const args = ['test', true, 1];
  118. api.handleRequestError(
  119. {
  120. id: 'test',
  121. path: 'test',
  122. requestOptions: {error: errorCb},
  123. },
  124. ...args
  125. );
  126. expect(errorCb).toHaveBeenCalledWith(...args);
  127. });
  128. it('handles undefined error callback', function () {
  129. expect(() =>
  130. api.handleRequestError(
  131. {
  132. id: 'test',
  133. path: 'test',
  134. requestOptions: {},
  135. },
  136. {},
  137. {}
  138. )
  139. ).not.toThrow();
  140. });
  141. describe('bulkUpdate()', function () {
  142. beforeEach(function () {
  143. jest.spyOn(api, '_wrapRequest');
  144. jest.spyOn(GroupActions, 'update'); // stub GroupActions.update call from api.update
  145. });
  146. it('should use itemIds as query if provided', function () {
  147. api.bulkUpdate({
  148. orgId: '1337',
  149. projectId: '1337',
  150. itemIds: [1, 2, 3],
  151. data: {status: 'unresolved'},
  152. query: 'is:resolved',
  153. });
  154. expect(api._wrapRequest).toHaveBeenCalledTimes(1);
  155. expect(api._wrapRequest).toHaveBeenCalledWith(
  156. '/projects/1337/1337/issues/',
  157. expect.objectContaining({query: {id: [1, 2, 3]}}),
  158. undefined
  159. );
  160. });
  161. it('should use query as query if itemIds are absent', function () {
  162. api.bulkUpdate({
  163. orgId: '1337',
  164. projectId: '1337',
  165. itemIds: null,
  166. data: {status: 'unresolved'},
  167. query: 'is:resolved',
  168. });
  169. expect(api._wrapRequest).toHaveBeenCalledTimes(1);
  170. expect(api._wrapRequest).toHaveBeenCalledWith(
  171. '/projects/1337/1337/issues/',
  172. expect.objectContaining({query: {query: 'is:resolved'}}),
  173. undefined
  174. );
  175. });
  176. it('should apply project option', function () {
  177. api.bulkUpdate({
  178. orgId: '1337',
  179. project: [99],
  180. itemIds: [1, 2, 3],
  181. data: {status: 'unresolved'},
  182. });
  183. expect(api._wrapRequest).toHaveBeenCalledTimes(1);
  184. expect(api._wrapRequest).toHaveBeenCalledWith(
  185. '/organizations/1337/issues/',
  186. expect.objectContaining({query: {id: [1, 2, 3], project: [99]}}),
  187. undefined
  188. );
  189. });
  190. });
  191. describe('merge()', function () {
  192. // TODO: this is totally copypasta from the test above. We need to refactor
  193. // these API methods/tests.
  194. beforeEach(function () {
  195. jest.spyOn(api, '_wrapRequest');
  196. jest.spyOn(GroupActions, 'merge'); // stub GroupActions.merge call from api.merge
  197. });
  198. it('should use itemIds as query if provided', function () {
  199. api.merge({
  200. orgId: '1337',
  201. projectId: '1337',
  202. itemIds: [1, 2, 3],
  203. data: {status: 'unresolved'},
  204. query: 'is:resolved',
  205. });
  206. expect(api._wrapRequest).toHaveBeenCalledTimes(1);
  207. expect(api._wrapRequest).toHaveBeenCalledWith(
  208. '/projects/1337/1337/issues/',
  209. expect.objectContaining({query: {id: [1, 2, 3]}}),
  210. undefined
  211. );
  212. });
  213. it('should use query as query if itemIds are absent', function () {
  214. api.merge({
  215. orgId: '1337',
  216. projectId: '1337',
  217. itemIds: null,
  218. data: {status: 'unresolved'},
  219. query: 'is:resolved',
  220. });
  221. expect(api._wrapRequest).toHaveBeenCalledTimes(1);
  222. expect(api._wrapRequest).toHaveBeenCalledWith(
  223. '/projects/1337/1337/issues/',
  224. expect.objectContaining({query: {query: 'is:resolved'}}),
  225. undefined
  226. );
  227. });
  228. });
  229. });