restangularSpec.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. describe("Restangular", function() {
  2. // API
  3. var Restangular, $httpBackend;
  4. var accountsModel, restangularAccounts, restangularAccount0, restangularAccount1;
  5. var accountsHalModel;
  6. var messages, newAccount;
  7. // Load required modules
  8. beforeEach(angular.mock.module("restangular"));
  9. // Init HTTP mock backend and Restangular resources
  10. beforeEach(inject(function($injector) {
  11. // Model
  12. accountsModel = [
  13. {id: 0, user: "Martin ", amount: 42, transactions: []},
  14. {id: 1, user: "Paul", amount: 3.1416, transactions: [{from: "Martin", amount: 3, id: 0}, {from: "Anonymous", amount: 0.1416, id:1}]}
  15. ];
  16. // HAL model (http://stateless.co/hal_specification.html)
  17. accountsHalModel = [
  18. {id: 0, user: "Martin", amount: 42, transaction: [], _links: {self: "/accountsHAL/martin"}},
  19. {id: 1, user: "Paul", amount: 3.1416, transaction: [
  20. {from: "Martin", amount: 3, id: 0, _links: {self: "/accountsHAL/paul/transactions/0"}},
  21. {from: "Anonymous", amount: 0.1416, id: 1, _links: {self: "/accountsHAL/paul/transactions/1"}}
  22. ], _links: {self: "/accountsHAL/paul"}}
  23. ];
  24. infoModel = {
  25. id: 0, text: "Some additional account information"
  26. }
  27. newAccount = {id: 44, user: "First User", amount: 45, transactions: []};
  28. messages = [{id: 23, name: "Gonto"}, {id: 45, name: "John"}]
  29. accountsDoSomethingModel = { result: 1 };
  30. $httpBackend = $injector.get("$httpBackend");
  31. $httpBackend.when("HEAD", "/accounts").respond();
  32. $httpBackend.when("TRACE", "/accounts").respond();
  33. $httpBackend.when("OPTIONS", "/accounts").respond();
  34. $httpBackend.whenGET("/accounts").respond(accountsModel);
  35. $httpBackend.whenGET("/accounts/do-something").respond(accountsDoSomethingModel);
  36. $httpBackend.whenJSONP("/accounts").respond(accountsModel);
  37. $httpBackend.whenGET("/accounts/0,1").respond(accountsModel);
  38. $httpBackend.whenGET("/accounts/messages").respond(messages);
  39. $httpBackend.whenGET("/accounts/1/message").respond(messages[0]);
  40. $httpBackend.whenGET("/accounts/1/messages").respond(messages);
  41. $httpBackend.whenGET("/accounts/0").respond(accountsModel[0]);
  42. $httpBackend.whenGET("/accounts/1").respond(accountsModel[1]);
  43. $httpBackend.whenJSONP("/accounts/1").respond(accountsModel[1]);
  44. $httpBackend.whenGET("/accounts/1/transactions").respond(accountsModel[1].transactions);
  45. $httpBackend.whenGET("/accounts/1/transactions/1").respond(accountsModel[1].transactions[1]);
  46. $httpBackend.whenGET("/info").respond(infoModel);
  47. $httpBackend.whenGET("/accounts/1/info").respond(infoModel);
  48. $httpBackend.whenPUT("/info").respond(function(method, url, data) {
  49. return [200, data, ""];
  50. });
  51. $httpBackend.whenGET("/accountsHAL").respond(accountsHalModel);
  52. $httpBackend.whenPUT("/accountsHAL/martin").respond(function(method, url, data) {
  53. accountsHalModel[0] = angular.fromJson(data);
  54. return [200, data, ""];
  55. });
  56. // Full URL
  57. $httpBackend.whenGET('http://accounts.com/all').respond(accountsModel);
  58. $httpBackend.whenPOST("/accounts").respond(function(method, url, data, headers) {
  59. var newData = angular.fromJson(data);
  60. newData.fromServer = true;
  61. return [201, JSON.stringify(newData), ""];
  62. });
  63. $httpBackend.whenPOST("/accounts/1/transactions").respond(function(method, url, data, headers) {
  64. return [201, "", ""];
  65. });
  66. $httpBackend.whenDELETE("/accounts/1/transactions/1").respond(function(method, url, data, headers) {
  67. return [200, "", ""];
  68. });
  69. $httpBackend.whenDELETE("/accounts/1").respond(function(method, url, data, headers) {
  70. return [200, "", ""];
  71. });
  72. $httpBackend.whenPOST("/accounts/1").respond(function(method, url, data, headers) {
  73. return [200, "", ""];
  74. });
  75. $httpBackend.whenPUT("/accounts/1").respond(function(method, url, data, headers) {
  76. accountsModel[1] = angular.fromJson(data);
  77. return [201, data, ""];
  78. });
  79. $httpBackend.whenGET("/error").respond(function() {
  80. return [500, {}, ""];
  81. });
  82. $httpBackend.whenPOST("/customs").respond(function(method, url, data, headers) {
  83. if (JSON.parse(data).one) {
  84. return [201, "", ""];
  85. } else {
  86. return [400, "", ""];
  87. }
  88. });
  89. // return the status code given
  90. // e.g.: /error/404 returns 404 Not Found
  91. var urlRegex = /\/error\/(\d{3})/;
  92. $httpBackend.whenGET(urlRegex).respond(function(method, url, data, headers) {
  93. return [url.match(urlRegex)[1], {}, ""];
  94. });
  95. Restangular = $injector.get("Restangular");
  96. restangularAccounts = Restangular.all("accounts");
  97. restangularAccount0 = Restangular.one("accounts", 0);
  98. restangularAccount1 = Restangular.one("accounts", 1);
  99. // Another API for testing
  100. customers = [
  101. {
  102. id: 0,
  103. name: "Alice",
  104. status: 'active',
  105. credit: 4000.0
  106. },
  107. {
  108. id: 1,
  109. name: "Bob",
  110. status: 'active',
  111. credit: 4000.0
  112. },
  113. {
  114. id: 2,
  115. name: "Carl",
  116. status: 'active',
  117. credit: 4000.0
  118. }
  119. ];
  120. publications = [
  121. {
  122. id: 1,
  123. title: "Sample",
  124. content: "Rich data",
  125. tags: [
  126. 'science',
  127. 'chemistry'
  128. ]
  129. }
  130. ];
  131. newCustomer = {
  132. id: 3,
  133. name: "New",
  134. status: 'active',
  135. credit: 4000.0
  136. };
  137. $httpBackend.whenGET("/customers/").respond(customers);
  138. $httpBackend.whenGET("http://localhost:8080/customers/").respond(customers);
  139. $httpBackend.whenGET("api.new.domain/customers/").respond(customers);
  140. $httpBackend.whenGET("/customers/?active=true").respond(customers);
  141. $httpBackend.whenGET("/customers/publications/?tags=chemistry").respond(publications);
  142. $httpBackend.whenPUT("/customers/0").respond(function (method, url, data) {
  143. customers[0] = angular.fromJson(data);
  144. return [200, data, ""];
  145. });
  146. $httpBackend.whenPOST("/customers/").respond(function (method, url, data, headers) {
  147. var newData = angular.fromJson(data);
  148. newData.fromServer = true;
  149. return [201, JSON.stringify(newData), ""];
  150. });
  151. }));
  152. afterEach(function() {
  153. $httpBackend.verifyNoOutstandingExpectation();
  154. $httpBackend.verifyNoOutstandingRequest();
  155. });
  156. describe("Interceptors", function() {
  157. it("Should add multiple request and response interceptors", function() {
  158. Restangular.addRequestInterceptor(function(elem) {
  159. var elemCopy = angular.copy(elem);
  160. elemCopy.firstRequestInterceptor = true;
  161. return elemCopy;
  162. });
  163. Restangular.addRequestInterceptor(function(elem) {
  164. expect(elem.firstRequestInterceptor).toBeDefined();
  165. var elemCopy = angular.copy(elem);
  166. elemCopy.secondRequestInterceptor = true;
  167. return elemCopy;
  168. });
  169. Restangular.addFullRequestInterceptor(function(elem) {
  170. expect(elem.firstRequestInterceptor).toBeDefined();
  171. expect(elem.secondRequestInterceptor).toBeDefined();
  172. var elemCopy = angular.copy(elem);
  173. elemCopy.thirdRequestInterceptor = true;
  174. return {
  175. element: elemCopy
  176. };
  177. });
  178. Restangular.addResponseInterceptor(function(elem) {
  179. var elemCopy = angular.copy(elem);
  180. elemCopy.firstResponseInterceptor = true;
  181. return elemCopy;
  182. });
  183. Restangular.addResponseInterceptor(function(elem) {
  184. expect(elem.firstResponseInterceptor).toBeDefined();
  185. var elemCopy = angular.copy(elem);
  186. elemCopy.secondResponseInterceptor = true;
  187. return elemCopy;
  188. });
  189. $httpBackend.whenPOST("/list").respond(function(method, url, data, headers) {
  190. var elem = angular.fromJson(data);
  191. expect(elem.firstRequestInterceptor).toBeDefined();
  192. expect(elem.secondRequestInterceptor).toBeDefined();
  193. expect(elem.thirdRequestInterceptor).toBeDefined();
  194. return [200, elem, ""];
  195. });
  196. $httpBackend.expectPOST('/list');
  197. Restangular.all('list').post({name: "Gonto"}).then(function(elem) {
  198. expect(elem.firstResponseInterceptor).toBeDefined();
  199. expect(elem.secondResponseInterceptor).toBeDefined();
  200. });
  201. $httpBackend.flush();
  202. });
  203. it("Should add multiple error interceptors", function() {
  204. $httpBackend.expectGET("/error");
  205. var CallbackManager = function() {};
  206. CallbackManager.successCallback = function() {
  207. expect(CallbackManager.successCallback).not.toHaveBeenCalled();
  208. };
  209. CallbackManager.errorCallback = function() {
  210. expect(CallbackManager.firstErrorInterceptor).toHaveBeenCalled();
  211. expect(CallbackManager.secondErrorInterceptor).toHaveBeenCalled();
  212. };
  213. CallbackManager.firstErrorInterceptor = function() {};
  214. CallbackManager.secondErrorInterceptor = function() {};
  215. spyOn(CallbackManager, "successCallback").andCallThrough();
  216. spyOn(CallbackManager, "firstErrorInterceptor").andCallThrough();
  217. spyOn(CallbackManager, "secondErrorInterceptor").andCallThrough();
  218. Restangular.addErrorInterceptor(CallbackManager.firstErrorInterceptor);
  219. Restangular.addErrorInterceptor(CallbackManager.secondErrorInterceptor);
  220. Restangular.all("error").getList()
  221. .then(CallbackManager.successCallback)
  222. .catch(CallbackManager.errorCallback);
  223. $httpBackend.flush();
  224. });
  225. it("Should add multiple error interceptors but don't reject the promise if one of them returns false", function() {
  226. $httpBackend.expectGET("/error");
  227. var CallbackManager = function() {};
  228. CallbackManager.successCallback = function() {
  229. expect(CallbackManager.successCallback).not.toHaveBeenCalled();
  230. };
  231. CallbackManager.errorCallback = function() {
  232. expect(CallbackManager.errorCallback).not.toHaveBeenCalled();
  233. };
  234. CallbackManager.firstErrorInterceptor = function() {
  235. return true;
  236. };
  237. CallbackManager.secondErrorInterceptor = function() {
  238. return false; // prevent promise to be rejected
  239. };
  240. spyOn(CallbackManager, "successCallback").andCallThrough();
  241. spyOn(CallbackManager, "errorCallback").andCallThrough();
  242. Restangular.addErrorInterceptor(CallbackManager.firstErrorInterceptor);
  243. Restangular.addErrorInterceptor(CallbackManager.secondErrorInterceptor);
  244. Restangular.all("error").getList()
  245. .then(CallbackManager.successCallback)
  246. .catch(CallbackManager.errorCallback);
  247. $httpBackend.flush();
  248. });
  249. it("Should add multiple error interceptors for a single get too", function() {
  250. $httpBackend.expectGET("/error/404");
  251. var CallbackManager = function() {};
  252. CallbackManager.successCallback = function() {
  253. expect(CallbackManager.successCallback).not.toHaveBeenCalled();
  254. };
  255. CallbackManager.errorCallback = function() {
  256. expect(CallbackManager.firstErrorInterceptor).toHaveBeenCalled();
  257. expect(CallbackManager.secondErrorInterceptor).toHaveBeenCalled();
  258. };
  259. CallbackManager.firstErrorInterceptor = function(response) {
  260. expect(response.status).toEqual(404);
  261. };
  262. CallbackManager.secondErrorInterceptor = function() {};
  263. spyOn(CallbackManager, "successCallback").andCallThrough();
  264. spyOn(CallbackManager, "firstErrorInterceptor").andCallThrough();
  265. spyOn(CallbackManager, "secondErrorInterceptor").andCallThrough();
  266. Restangular.addErrorInterceptor(CallbackManager.firstErrorInterceptor);
  267. Restangular.addErrorInterceptor(CallbackManager.secondErrorInterceptor);
  268. Restangular.one("error", 404).get()
  269. .then(CallbackManager.successCallback)
  270. .catch(CallbackManager.errorCallback);
  271. $httpBackend.flush();
  272. });
  273. });
  274. describe("Transformers", function() {
  275. it("Should decorate element both on server and local by default", function() {
  276. Restangular.extendModel('accounts', function(account) {
  277. account.extended = function() {return true;}
  278. return account;
  279. });
  280. Restangular.one('accounts', 1).get().then(function(account) {
  281. expect(account.extended).toBeDefined();
  282. });
  283. var local = {};
  284. Restangular.restangularizeElement(null, local, 'accounts');
  285. expect(local.extended).toBeDefined();
  286. $httpBackend.flush();
  287. });
  288. });
  289. describe("With Suffix", function() {
  290. it("shouldn't add suffix to getRestangularUrl", function() {
  291. var suffixRestangular = Restangular.withConfig(function(RestangularConfigurer) {
  292. RestangularConfigurer.setRequestSuffix('.json');
  293. });
  294. var collection = suffixRestangular.all('accounts');
  295. expect(collection.getRestangularUrl()).toBe('/accounts');
  296. expect(collection.one('1').getRestangularUrl()).toBe('/accounts/1');
  297. });
  298. it("should add suffix to getRequestedUrl", function() {
  299. var suffixRestangular = Restangular.withConfig(function(RestangularConfigurer) {
  300. RestangularConfigurer.setRequestSuffix('.json');
  301. });
  302. var collection = suffixRestangular.all('accounts');
  303. expect(collection.getRequestedUrl()).toBe('/accounts.json');
  304. expect(collection.one('1').getRequestedUrl()).toBe('/accounts/1.json');
  305. });
  306. it("should add suffix to request", function() {
  307. var suffixRestangular = Restangular.withConfig(function(RestangularConfigurer) {
  308. RestangularConfigurer.setRequestSuffix('.json');
  309. });
  310. var collection = suffixRestangular.all('accounts');
  311. $httpBackend.expectGET('/accounts.json').respond(200);
  312. $httpBackend.expectGET('/accounts/1.json').respond(200);
  313. collection.getList();
  314. collection.get('1');
  315. $httpBackend.flush();
  316. });
  317. it("shouldn't add suffix to allUrl", function() {
  318. var suffixRestangular = Restangular.withConfig(function(RestangularConfigurer) {
  319. RestangularConfigurer.setRequestSuffix('.json');
  320. });
  321. $httpBackend.expectGET('http://accounts.com/all');
  322. suffixRestangular.allUrl('accounts', 'http://accounts.com/all').getList();
  323. $httpBackend.flush();
  324. });
  325. });
  326. describe("JSONp", function() {
  327. it("should work for get", function() {
  328. Restangular.setJsonp(true);
  329. Restangular.one('accounts', 1).get();
  330. $httpBackend.expectJSONP('/accounts/1');
  331. $httpBackend.flush();
  332. });
  333. it("should work for getList", function() {
  334. Restangular.setJsonp(true);
  335. Restangular.all('accounts').getList();
  336. $httpBackend.expectJSONP('/accounts');
  337. $httpBackend.flush();
  338. });
  339. it("shouldn't override post", function() {
  340. Restangular.setJsonp(true);
  341. restangularAccounts.post({id: 2, user: "Someone"});
  342. $httpBackend.expectPOST('/accounts').respond(201, '');
  343. $httpBackend.flush();
  344. });
  345. });
  346. describe("Local data", function() {
  347. it("Should restangularize a collection OK", function() {
  348. var collection = angular.copy(accountsModel);
  349. Restangular.restangularizeCollection(null, collection, 'accounts');
  350. expect(_.has(collection, 'get')).toBe(true);
  351. expect(_.has(collection[0], 'get')).toBe(true);
  352. expect(collection.getRestangularUrl()).toBe('/accounts');
  353. expect(collection[0].getRestangularUrl()).toBe('/accounts/0');
  354. });
  355. });
  356. describe("restangularizePromiseIntercept", function() {
  357. it("should be invoked by restangularizePromise", function() {
  358. var calledWithPromise;
  359. Restangular.setRestangularizePromiseInterceptor(function(promise) {
  360. calledWithPromise = promise;
  361. promise.$object.$custom = true;
  362. });
  363. var promise = Restangular.one('accounts', 1).get();
  364. expect(calledWithPromise).toBeDefined();
  365. expect(promise.$object.$custom).toBeDefined();
  366. $httpBackend.flush();
  367. });
  368. });
  369. describe("$object", function() {
  370. it("Should work for single get", function() {
  371. var promise = Restangular.one('accounts', 1).get();
  372. var obj = promise.$object;
  373. expect(obj).toBeDefined();
  374. expect(obj.amount).toBeUndefined();
  375. $httpBackend.flush();
  376. expect(obj.amount).toEqual(3.1416);
  377. });
  378. it("Shouldn't be restangularized by default", function() {
  379. Restangular.extendModel('accounts', function(account) {
  380. account.extended = function() {return true;}
  381. return account;
  382. });
  383. var promise = Restangular.one('accounts', 1).get();
  384. var obj = promise.$object;
  385. expect(obj).toBeDefined();
  386. expect(obj.extended).toBeUndefined();
  387. $httpBackend.flush();
  388. });
  389. it("Should work for single get", function() {
  390. var promise = Restangular.all('accounts').getList();
  391. var list = promise.$object;
  392. expect(list).toBeDefined();
  393. expect(list.length).toEqual(0);
  394. $httpBackend.flush();
  395. expect(list.length).toEqual(2);
  396. expect(list[1].amount).toEqual(3.1416);
  397. });
  398. });
  399. describe("ALL", function() {
  400. it("getList() should return an array of items", function() {
  401. restangularAccounts.getList().then(function(accounts) {
  402. expect(Restangular.stripRestangular(accounts)).toEqual(Restangular.stripRestangular(accountsModel));
  403. });
  404. $httpBackend.flush();
  405. });
  406. it("several getList() should return an array of items", function() {
  407. $httpBackend.expectGET('/accounts/0,1');
  408. Restangular.several("accounts", 0, 1).getList().then(function(accounts) {
  409. expect(Restangular.stripRestangular(accounts)).toEqual(Restangular.stripRestangular(accountsModel));
  410. });
  411. $httpBackend.flush();
  412. });
  413. it("several remove() should work", function() {
  414. $httpBackend.expectDELETE('/accounts/0,1').respond([200, "", ""]);
  415. Restangular.several("accounts", 0, 1).remove();
  416. $httpBackend.flush();
  417. });
  418. it("get(id) should return the item with given id", function() {
  419. restangularAccounts.get(0).then(function(account) {
  420. expect(Restangular.stripRestangular(account)).toEqual(Restangular.stripRestangular(accountsModel[0]));
  421. });
  422. $httpBackend.flush();
  423. });
  424. it('uses all to get the list without parameters', function() {
  425. Restangular.one('accounts', 1).all('messages').getList();
  426. $httpBackend.expectGET('/accounts/1/messages');
  427. $httpBackend.flush();
  428. });
  429. it("Custom GET methods should work", function() {
  430. restangularAccounts.customGETLIST("messages").then(function(msgs) {
  431. expect(Restangular.stripRestangular(msgs)).toEqual(Restangular.stripRestangular(messages));
  432. });
  433. $httpBackend.flush();
  434. });
  435. it("post() should add a new item", function() {
  436. restangularAccounts.post({id: 2, user: "Someone"}).then(function() {
  437. expect(accountsModel.length).toEqual(2);
  438. });
  439. $httpBackend.expectPOST('/accounts').respond(201, '');
  440. $httpBackend.flush();
  441. });
  442. it("customPOST() should add a new item", function() {
  443. restangularAccounts.customPOST({id: 2, user: "Someone"}).then(function() {
  444. expect(accountsModel.length).toEqual(2);
  445. });
  446. $httpBackend.expectPOST('/accounts').respond(201, '');
  447. $httpBackend.flush();
  448. });
  449. it("post() should work with arrays", function() {
  450. Restangular.all('places').post([{name: "Gonto"}, {name: 'John'}]).then(function(value) {
  451. expect(value.length).toEqual(2);
  452. });
  453. $httpBackend.expectPOST('/places').respond(function(method, url, data, headers) {
  454. return [201, angular.fromJson(data), ""];
  455. });
  456. $httpBackend.flush();
  457. });
  458. it("post() should add a new item with data and return the data from the server", function() {
  459. restangularAccounts.post(newAccount).then(function(added) {
  460. expect(added.fromServer).toEqual(true);
  461. expect(added.id).toEqual(newAccount.id);
  462. });
  463. $httpBackend.expectPOST('/accounts');
  464. $httpBackend.flush();
  465. });
  466. it("Doing a post and then other operation (delete) should call right URLs", function() {
  467. restangularAccounts.post(newAccount).then(function(added) {
  468. added.remove();
  469. $httpBackend.expectDELETE('/accounts/44').respond(201, '');
  470. });
  471. $httpBackend.flush();
  472. });
  473. it("Doing a post to a server that returns no element will return undefined", function() {
  474. restangularAccounts.getList().then(function(accounts) {
  475. var newTransaction = {id: 1, name: "Gonto"};
  476. accounts[1].post('transactions', newTransaction).then(function(transaction) {
  477. expect(transaction).toBeUndefined();
  478. });
  479. });
  480. $httpBackend.flush();
  481. });
  482. it("head() should safely return", function() {
  483. restangularAccounts.head().then(function() {
  484. expect(true).toBe(true);
  485. });
  486. $httpBackend.flush();
  487. });
  488. it("trace() should safely return", function() {
  489. restangularAccounts.trace().then(function() {
  490. expect(true).toBe(true);
  491. });
  492. $httpBackend.flush();
  493. });
  494. it("customPUT should work", function() {
  495. $httpBackend.expectPUT('/accounts/hey').respond(accountsModel);
  496. restangularAccounts.customPUT({key: 'value'}, 'hey');
  497. $httpBackend.flush();
  498. });
  499. it("options() should safely return", function() {
  500. restangularAccounts.options().then(function() {
  501. expect(true).toBe(true);
  502. });
  503. $httpBackend.flush();
  504. });
  505. it("getList() should correctly handle params after customDELETE", function() {
  506. $httpBackend.expectGET('/accounts?foo=1').respond(accountsModel);
  507. restangularAccounts.getList({foo: 1}).then(function(){
  508. $httpBackend.expectDELETE('/accounts?id=1').respond(201, '');
  509. return restangularAccounts.customDELETE('', {id: 1});
  510. }).then(function() {
  511. $httpBackend.expectGET('/accounts?foo=1').respond(accountsModel);
  512. return restangularAccounts.getList({foo: 1});
  513. }).then(function(accounts) {
  514. expect(Restangular.stripRestangular(accounts)).toEqual(Restangular.stripRestangular(accountsModel));
  515. });
  516. $httpBackend.flush();
  517. });
  518. });
  519. describe("Scoped Service", function() {
  520. it("should correctly work", function() {
  521. var Accounts = Restangular.service('accounts');
  522. Accounts.post(newAccount);
  523. Accounts.one(0).get();
  524. Accounts.getList();
  525. $httpBackend.expectPOST('/accounts');
  526. $httpBackend.expectGET('/accounts/0');
  527. $httpBackend.expectGET('/accounts');
  528. $httpBackend.flush();
  529. });
  530. it("should correctly work with children", function() {
  531. var Transactions = Restangular.service('transactions', restangularAccount1);
  532. Transactions.post(newAccount);
  533. Transactions.one(1).get();
  534. Transactions.getList();
  535. $httpBackend.expectPOST('/accounts/1/transactions');
  536. $httpBackend.expectGET('/accounts/1/transactions/1');
  537. $httpBackend.expectGET('/accounts/1/transactions');
  538. $httpBackend.flush();
  539. });
  540. it("should add custom collection method added with withConfig", function() {
  541. var Accounts = Restangular.withConfig(function(RestangularConfigurer) {
  542. RestangularConfigurer.addElementTransformer('accounts', true, function(worker) {
  543. worker.addRestangularMethod('doSomething', 'get', 'do-something');
  544. return worker;
  545. });
  546. }).service('accounts');
  547. expect(Accounts.doSomething).toBeDefined();
  548. expect(_.isFunction(Accounts.doSomething)).toBeTruthy();
  549. Accounts.post(newAccount);
  550. Accounts.one(0).get();
  551. Accounts.getList();
  552. Accounts.doSomething();
  553. $httpBackend.expectPOST('/accounts');
  554. $httpBackend.expectGET('/accounts/0');
  555. $httpBackend.expectGET('/accounts');
  556. $httpBackend.expectGET('/accounts/do-something');
  557. $httpBackend.flush();
  558. });
  559. });
  560. describe("ONE", function() {
  561. it("get() should return a JSON item", function() {
  562. restangularAccount1.get().then(function(account) {
  563. expect(Restangular.stripRestangular(account))
  564. .toEqual(Restangular.stripRestangular(accountsModel[1]));
  565. });
  566. $httpBackend.flush();
  567. });
  568. it("Should save as put correctly", function() {
  569. restangularAccount1.get().then(function(account) {
  570. $httpBackend.expectPUT('/accounts/1');
  571. account.put();
  572. });
  573. $httpBackend.flush();
  574. });
  575. it("Should save as post correctly", function() {
  576. var account1 = angular.copy(restangularAccount1);
  577. $httpBackend.expectPOST('/accounts/1');
  578. account1.name = "Hey";
  579. account1.save();
  580. $httpBackend.flush();
  581. });
  582. it("Should keep route property when element is created", function() {
  583. var account1 = Restangular.restangularizeElement(null, {}, 'accounts');
  584. $httpBackend.expectPOST('/accounts');
  585. $httpBackend.expectPUT('/accounts/1');
  586. account1.name = "Hey";
  587. account1.save().then(function(accountFromServer) {
  588. accountFromServer.id = 1;
  589. return accountFromServer.save();
  590. }).then(function(accountFromServer2) {
  591. expect(accountFromServer2.route).toBe(account1.route);
  592. });
  593. $httpBackend.flush()
  594. });
  595. it("Should make RequestLess connections with one", function() {
  596. restangularAccount1.one("transactions", 1).get().then(function(transaction) {
  597. expect(Restangular.stripRestangular(transaction))
  598. .toEqual(Restangular.stripRestangular(accountsModel[1].transactions[1]));
  599. });
  600. $httpBackend.flush();
  601. });
  602. it("Should make RequestLess connections with all", function() {
  603. restangularAccount1.all("transactions").getList().then(function(transactions) {
  604. expect(Restangular.stripRestangular(transactions))
  605. .toEqual(Restangular.stripRestangular(accountsModel[1].transactions));
  606. });
  607. $httpBackend.flush();
  608. });
  609. it("Custom GET methods should work", function() {
  610. restangularAccount1.customGET("message").then(function(msg) {
  611. expect(Restangular.stripRestangular(msg)).toEqual(Restangular.stripRestangular(messages[0]));
  612. });
  613. $httpBackend.flush();
  614. });
  615. it("put() should update the value", function() {
  616. restangularAccount1.get().then(function(account) {
  617. account.amount = 1.618;
  618. account.put().then(function(newAc) {
  619. expect(accountsModel[1].amount).toEqual(1.618);
  620. newAc.remove();
  621. $httpBackend.expectDELETE("/accounts/1");
  622. });
  623. $httpBackend.expectPUT("/accounts/1");
  624. });
  625. $httpBackend.flush();
  626. });
  627. it("should return an array when accessing a subvalue", function() {
  628. restangularAccount1.get().then(function(account) {
  629. account.getList("transactions").then(function(transactions) {
  630. expect(Restangular.stripRestangular(transactions))
  631. .toEqual(Restangular.stripRestangular(accountsModel[1].transactions));
  632. });
  633. });
  634. $httpBackend.flush();
  635. });
  636. });
  637. describe("COPY", function() {
  638. it("should copy an object and 'this' should reference the copied object", function() {
  639. var copiedAccount = Restangular.copy(accountsModel[0]);
  640. var that;
  641. copiedAccount.user = "Copied string";
  642. expect(copiedAccount).not.toBe(accountsModel[0]);
  643. // create a spy for one of the methods to capture the value of 'this'
  644. spyOn(copiedAccount, 'getRestangularUrl').andCallFake(function() {
  645. that = this;
  646. });
  647. copiedAccount.getRestangularUrl(); // invoke the method we are spying on
  648. expect(that).toBe(copiedAccount);
  649. });
  650. });
  651. describe("getRestangularUrl", function() {
  652. it("should return the generated URL when you chain Restangular methods together", function() {
  653. var restangularSpaces = Restangular.one("accounts",123).one("buildings", 456).all("spaces");
  654. expect(restangularSpaces.getRestangularUrl()).toEqual("/accounts/123/buildings/456/spaces");
  655. });
  656. });
  657. describe("getRestangularUrl with useCannonicalId set to true", function() {
  658. it("should return the generated URL when you chain Restangular methods together", function() {
  659. var R = Restangular.withConfig(function(config) {
  660. config.setUseCannonicalId(true);
  661. });
  662. var restangularSpaces = R.one("accounts",123).one("buildings", 456).all("spaces");
  663. expect(restangularSpaces.getRestangularUrl()).toEqual("/accounts/123/buildings/456/spaces");
  664. });
  665. });
  666. describe("addElementTransformer", function() {
  667. it("should allow for a custom method to be placed at the collection level", function() {
  668. var accountsPromise;
  669. Restangular.addElementTransformer('accounts', true, function(collection) {
  670. collection.totalAmount = function() {};
  671. return collection;
  672. });
  673. accountsPromise = Restangular.all('accounts').getList();
  674. accountsPromise.then(function(accounts) {
  675. expect(typeof accounts.totalAmount).toEqual("function");
  676. });
  677. $httpBackend.flush();
  678. });
  679. it("should allow for a custom method to be placed at the model level when one model is requested", function() {
  680. var accountPromise;
  681. Restangular.addElementTransformer('accounts', false, function(model) {
  682. model.prettifyAmount = function() {};
  683. return model;
  684. });
  685. accountPromise = Restangular.one('accounts', 1).get();
  686. accountPromise.then(function(account) {
  687. expect(typeof account.prettifyAmount).toEqual("function");
  688. });
  689. $httpBackend.flush();
  690. });
  691. it("should allow for a custom method to be placed at the model level when several models are requested", function() {
  692. var accountPromise;
  693. Restangular.addElementTransformer('accounts', false, function(model) {
  694. model.prettifyAmount = function() {};
  695. return model;
  696. });
  697. accountsPromise = Restangular.all('accounts', 1).getList();
  698. accountsPromise.then(function(accounts) {
  699. accounts.forEach(function(account, index) {
  700. expect(typeof account.prettifyAmount).toEqual("function");
  701. });
  702. });
  703. $httpBackend.flush();
  704. });
  705. });
  706. describe("extendCollection", function() {
  707. it("should be an alias for a specific invocation of addElementTransformer", function() {
  708. var spy = spyOn(Restangular, 'addElementTransformer');
  709. var fn = function(collection) {
  710. collection.totalAmount = function() {};
  711. return collection;
  712. };
  713. Restangular.extendCollection('accounts', fn);
  714. expect(spy).toHaveBeenCalledWith('accounts', true, fn);
  715. });
  716. });
  717. describe("extendModel", function() {
  718. it("should be an alias for a specific invocation of addElementTransformer", function() {
  719. var spy = spyOn(Restangular, 'addElementTransformer');
  720. var fn = function(model) {
  721. model.prettifyAmount = function() {};
  722. return model;
  723. };
  724. Restangular.extendModel('accounts', fn);
  725. expect(spy).toHaveBeenCalledWith('accounts', false, fn);
  726. });
  727. });
  728. describe("headers", function() {
  729. it("should return defaultHeaders", function() {
  730. var defaultHeaders = {testheader:'header value'};
  731. Restangular.setDefaultHeaders(defaultHeaders);
  732. expect(Restangular.defaultHeaders).toEqual(defaultHeaders);
  733. });
  734. it("should pass uppercase methods in X-HTTP-Method-Override", function() {
  735. Restangular.setMethodOverriders(["put"]);
  736. $httpBackend.expectPOST('/overriders/1').respond(function(method, url, data, headers) {
  737. expect(headers['X-HTTP-Method-Override']).toBe('PUT');
  738. return {};
  739. });
  740. Restangular.one('overriders', 1).put();
  741. $httpBackend.flush();
  742. });
  743. });
  744. describe("defaultRequestParams", function() {
  745. it("should return defaultRequestParams", function() {
  746. var defaultRequestParams = {param:'value'};
  747. Restangular.setDefaultRequestParams(defaultRequestParams);
  748. expect(Restangular.requestParams.common).toEqual(defaultRequestParams);
  749. });
  750. it("should be able to set default params for get, post, put.. methods separately", function() {
  751. var postParams = {post:'value'},
  752. putParams = {put:'value'};
  753. Restangular.setDefaultRequestParams('post', postParams);
  754. expect(Restangular.requestParams.post).toEqual(postParams);
  755. Restangular.setDefaultRequestParams('put', putParams);
  756. expect(Restangular.requestParams.put).toEqual(putParams);
  757. expect(Restangular.requestParams.common).not.toEqual(putParams);
  758. });
  759. it("should be able to set default params for multiple methods with array", function() {
  760. var defaultParams = {param:'value'};
  761. Restangular.setDefaultRequestParams(['post', 'put'], defaultParams);
  762. expect(Restangular.requestParams.post).toEqual(defaultParams);
  763. expect(Restangular.requestParams.put).toEqual(defaultParams);
  764. expect(Restangular.requestParams.common).not.toEqual(defaultParams);
  765. });
  766. });
  767. describe("withConfig", function() {
  768. it("should create new service with scoped configuration", function() {
  769. var childRestangular = Restangular.withConfig(function(RestangularConfigurer){
  770. RestangularConfigurer.setBaseUrl('/api/v1');
  771. });
  772. expect(Restangular.configuration.baseUrl).toEqual('');
  773. expect(childRestangular.configuration.baseUrl).toEqual('/api/v1');
  774. });
  775. it("should allow nested configurations", function() {
  776. var childRestangular = Restangular.withConfig(function(RestangularConfigurer){
  777. RestangularConfigurer.setBaseUrl('/api/v1');
  778. });
  779. var grandchildRestangular = childRestangular.withConfig(function(RestangularConfigurer){
  780. RestangularConfigurer.setRequestSuffix('.json');
  781. });
  782. expect(Restangular.configuration.baseUrl).toEqual('');
  783. expect(Restangular.configuration.suffix).toEqual(null);
  784. expect(childRestangular.configuration.baseUrl).toEqual('/api/v1');
  785. expect(childRestangular.configuration.suffix).toEqual(null);
  786. expect(grandchildRestangular.configuration.baseUrl).toEqual('/api/v1');
  787. expect(grandchildRestangular.configuration.suffix).toEqual('.json');
  788. });
  789. });
  790. describe("Self linking", function() {
  791. it("Should request the link in HAL format", function() {
  792. var linkRestangular = Restangular.withConfig(function(RestangularConfigurer) {
  793. RestangularConfigurer.setRestangularFields({
  794. selfLink: "_links.self"
  795. });
  796. });
  797. var arr = linkRestangular.all('accountsHAL').getList().$object;
  798. $httpBackend.flush();
  799. var account = arr[0];
  800. $httpBackend.expectPUT("/accountsHAL/martin");
  801. account.name = "Updated";
  802. account.put();
  803. $httpBackend.flush();
  804. });
  805. });
  806. describe("Singe one (endpoint not expecting an id)", function() {
  807. it('does not use the id for single resource GET', function() {
  808. Restangular.one('info', 0, true).get();
  809. $httpBackend.expectGET('/info');
  810. $httpBackend.flush();
  811. });
  812. it('getRestangularUrl() returns still the url without id after GET', function() {
  813. record = Restangular.one('info', 0, true);
  814. record.get().then(function(data){
  815. expect(data.getRestangularUrl()).toEqual("/info")
  816. });
  817. $httpBackend.expectGET('/info');
  818. $httpBackend.flush();
  819. });
  820. it('does not use the id for single nested resource GET', function() {
  821. Restangular.one('accounts', 1).one('info', 0, true).get()
  822. $httpBackend.expectGET('/accounts/1/info');
  823. $httpBackend.flush();
  824. });
  825. it('does not use the id for single resource PUT', function() {
  826. Restangular.one('info', 0, true).put();
  827. $httpBackend.expectPUT('/info');
  828. $httpBackend.flush();
  829. });
  830. });
  831. describe("setSelfLinkAbsoluteUrl", function() {
  832. it("works", function() {
  833. var childRestangular = Restangular.withConfig(function(RestangularConfigurer){
  834. RestangularConfigurer.setSelfLinkAbsoluteUrl(false);
  835. });
  836. expect(Restangular.configuration.absoluteUrl).toEqual(true);
  837. expect(childRestangular.configuration.absoluteUrl).toEqual(false);
  838. })
  839. });
  840. describe("Misc", function () {
  841. it("should not strip [one] or [all] key from plain object", function () {
  842. Restangular.all("customs").customPOST({one: 'I am here', two: 'I am also here'}).then(function () {
  843. expect(1).toBe(1);
  844. }, function () {
  845. expect("Promise").toBe("correctly fulfilled");
  846. });
  847. $httpBackend.flush();
  848. });
  849. it("should not stip non-restangularized elements", function () {
  850. expect(Restangular.stripRestangular(["test","test2"])).toEqual(["test","test2"]);
  851. });
  852. });
  853. describe("testing normilize url", function () {
  854. it("should get a list of objects", function () {
  855. Restangular.all('customers/').getList().then(function(res){
  856. res.getList({active: true});
  857. $httpBackend.expectGET('/customers/?active=true');
  858. //res.getList('publications/', {tags: 'chemistry'});
  859. //$httpBackend.expectGET('/customers/publications/?tags=chemistry');
  860. });
  861. $httpBackend.expectGET('/customers/');
  862. $httpBackend.flush();
  863. });
  864. it("should get a list of objects even if the path has extra slashes", function () {
  865. Restangular.all('customers///').getList().then(function(res){
  866. res.getList({active: true});
  867. $httpBackend.expectGET('/customers/?active=true');
  868. });
  869. $httpBackend.expectGET('/customers/');
  870. $httpBackend.flush();
  871. });
  872. it("should post with slash at the end", function () {
  873. Restangular.all('customers/').getList().then(function(res){
  874. res.post(newCustomer);
  875. $httpBackend.expectPOST('/customers/');
  876. });
  877. $httpBackend.expectGET('/customers/');
  878. $httpBackend.flush();
  879. });
  880. it("should put with slash at the end", function () {
  881. Restangular.all('customers/').getList().then(function(customers){
  882. customers[0].put();
  883. $httpBackend.expectPUT('/customers/0');
  884. });
  885. $httpBackend.flush();
  886. });
  887. it("should return a normilized URL even it has extra slashes", function() {
  888. var restangularSpaces = Restangular.one("accounts//", 123).one("buildings//", 456).all("spaces///");
  889. expect(restangularSpaces.getRestangularUrl()).toEqual("/accounts/123/buildings/456/spaces/");
  890. });
  891. it("should create a new service and still working normilized URL", function() {
  892. var newRes = Restangular.withConfig(function(RestangularConfigurer){
  893. RestangularConfigurer.setBaseUrl('http://localhost:8080');
  894. });
  895. expect(newRes.configuration.baseUrl).toEqual('http://localhost:8080');
  896. newRes.all("customers////").getList();
  897. $httpBackend.expectGET('http://localhost:8080/customers/');
  898. var newApi = Restangular.withConfig(function(RestangularConfigurer){
  899. RestangularConfigurer.setBaseUrl('api.new.domain');
  900. });
  901. expect(newApi.configuration.baseUrl).toEqual('api.new.domain');
  902. newApi.all("customers////").getList();
  903. $httpBackend.expectGET('api.new.domain/customers/');
  904. $httpBackend.flush();
  905. });
  906. });
  907. });