From bc769dc9325362590f1b95d08f2cb01330a4bc1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Bostr=C3=B6m?= Date: Sat, 14 Jan 2017 13:04:52 +0200 Subject: [PATCH 1/6] test(ETags): add tests for ETag headers and setPlainByDefault As reported in #1453 --- test/restangularSpec.js | 140 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 9 deletions(-) diff --git a/test/restangularSpec.js b/test/restangularSpec.js index 13452748..61db1fcb 100644 --- a/test/restangularSpec.js +++ b/test/restangularSpec.js @@ -1501,30 +1501,152 @@ describe('Restangular', function () { }); describe('setPlainByDefault', function () { + var plainByDefaultRestangular; - it('should not add restangularized methods to response object', function () { - var newRes = Restangular.withConfig(function (RestangularConfigurer) { + beforeEach(function () { + plainByDefaultRestangular = Restangular.withConfig(function (RestangularConfigurer) { RestangularConfigurer.setPlainByDefault(true); }); + }); - expect(newRes.configuration.plainByDefault).toEqual(true); + it('should set the property on the configuration', function () { + expect(plainByDefaultRestangular.configuration.plainByDefault).toEqual(true); + }); - newRes.one('accounts', 0).get().then(function (account) { + it('should not add restangularized methods to response object', function () { + plainByDefaultRestangular.one('accounts', 0).get().then(function (account) { expect(account).toEqual(testData.accountsModel[0]); }); - $httpBackend.flush(); }); it('shoud not add restangularized methods to response collection', function () { - var newRes = Restangular.withConfig(function (RestangularConfigurer) { - RestangularConfigurer.setPlainByDefault(true); + plainByDefaultRestangular.all('accounts').getList().then(function (accounts) { + expect(accounts).toEqual(testData.accountsModel); }); + $httpBackend.flush(); + }); - newRes.all('accounts').getList().then(function (accounts) { - expect(accounts).toEqual(testData.accountsModel); + describe('with ETag', function () { + beforeEach(function () { + $httpBackend.whenGET('/accounts').respond( + testData.accountsModel, + {'ETag': 'c11ea3f8-3bfd-4be8-a6a6-501dd831b8a4'} + ); + $httpBackend.whenGET('/accounts/1').respond( + testData.accountsModel[1], + {'ETag': 'bf79b780-f132-4f44-a9eb-7e6eb4f902b2'} + ); + }); + + it('should not add restangularized ETag to response object', function () { + plainByDefaultRestangular.one('accounts', 0).get().then(function (account) { + expect(account).toEqual(testData.accountsModel[0]); + }); + $httpBackend.flush(); + }); + + it('shoud not add restangularized ETag to response collection', function () { + plainByDefaultRestangular.all('accounts').getList().then(function (accounts) { + expect(accounts).toEqual(testData.accountsModel); + }); + $httpBackend.flush(); + }); + }); + }); + + describe('ETags', function () { + beforeEach(function () { + $httpBackend.whenGET('/etagAccounts').respond( + testData.accountsModel, + {'ETag': 'c11ea3f8-3bfd-4be8-a6a6-501dd831b8a4'} + ); + $httpBackend.whenGET('/etagAccounts/1').respond( + testData.accountsModel[1], + {'ETag': 'bf79b780-f132-4f44-a9eb-7e6eb4f902b2'} + ); + }); + + it('should include the ETag in the restangularized element', function () { + Restangular.one('etagAccounts', 1).get().then(function (account) { + expect(account.restangularEtag).toEqual('bf79b780-f132-4f44-a9eb-7e6eb4f902b2'); + }); + $httpBackend.flush(); + }); + it('should include the ETag in the restangularized collection', function () { + Restangular.all('etagAccounts').getList().then(function (accounts) { + expect(accounts.restangularEtag).toEqual('c11ea3f8-3bfd-4be8-a6a6-501dd831b8a4'); }); $httpBackend.flush(); }); + it('should add the If-Match header on PUT requests', function () { + var responseHandler = jasmine.createSpy(); + Restangular.one('etagAccounts', 1).get().then(responseHandler); + $httpBackend.flush(); + + var account = responseHandler.calls.argsFor(0)[0]; + $httpBackend.expect( + 'PUT', + '/etagAccounts/1', + testData.accountsModel[1], + function (headers) { + return headers['If-Match'] === 'bf79b780-f132-4f44-a9eb-7e6eb4f902b2'; + } + ).respond(200); + account.save(); + $httpBackend.flush(); + }); + it('should add the If-Match header on DELETE requests', function () { + var responseHandler = jasmine.createSpy(); + Restangular.one('etagAccounts', 1).get().then(responseHandler); + $httpBackend.flush(); + + var account = responseHandler.calls.argsFor(0)[0]; + $httpBackend.expect( + 'DELETE', + '/etagAccounts/1', + testData.accountsModel[1], + function (headers) { + return headers['If-Match'] === 'bf79b780-f132-4f44-a9eb-7e6eb4f902b2'; + } + ).respond(200); + account.remove(); + $httpBackend.flush(); + }); + it('should add the If-None-Match header on GET requests for elements', function () { + var responseHandler = jasmine.createSpy(); + Restangular.one('etagAccounts', 1).get().then(responseHandler); + $httpBackend.flush(); + + var account = responseHandler.calls.argsFor(0)[0]; + $httpBackend.expect( + 'GET', + '/etagAccounts/1', + undefined, + function (headers) { + return headers['If-None-Match'] === 'bf79b780-f132-4f44-a9eb-7e6eb4f902b2'; + } + ).respond(200); + account.get(); + $httpBackend.flush(); + }); + it('should add the If-None-Match header on GET requests for collections', function () { + var responseHandler = jasmine.createSpy(); + Restangular.all('etagAccounts').getList().then(responseHandler); + $httpBackend.flush(); + + var accounts = responseHandler.calls.argsFor(0)[0]; + $httpBackend.expect( + 'GET', + '/etagAccounts', + undefined, + function (headers) { + return headers['If-None-Match'] === 'c11ea3f8-3bfd-4be8-a6a6-501dd831b8a4'; + } + ).respond(200); + accounts.getList(); + $httpBackend.flush(); + }); + }); }); From aac96122a2480ed1538b18aefb56e844f6fc0b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Bostr=C3=B6m?= Date: Sat, 14 Jan 2017 19:28:53 +0200 Subject: [PATCH 2/6] test(getRestangularUrl): add tests for getRestangularUrl As per #1421 --- test/restangularSpec.js | 80 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/test/restangularSpec.js b/test/restangularSpec.js index 13452748..c648b0c8 100644 --- a/test/restangularSpec.js +++ b/test/restangularSpec.js @@ -1075,23 +1075,87 @@ describe('Restangular', function () { }); describe('getRestangularUrl', function () { + it('should get the URL for the current object', function () { + var element = Restangular.one('accounts', 123); + expect(element.getRestangularUrl()).toEqual('/accounts/123'); + }); + it('should not include query parameters', function () { + var responseHandler = jasmine.createSpy(), element; + $httpBackend.expectGET('/accounts/123?query=params').respond({id: 123, name: 'account123'}); + Restangular.one('accounts', 123).get({query: 'params'}).then(responseHandler); + $httpBackend.flush(); + + element = responseHandler.calls.argsFor(0)[0]; + expect(element.getRestangularUrl()).toEqual('/accounts/123'); + }); + it('should be the same for the built resource as for the fetched resource', function () { + var responseHandler = jasmine.createSpy(), element, resource; + $httpBackend.expectGET('/accounts/123').respond({id: 123, name: 'Account 123'}); + resource = Restangular.one('accounts', 123); + resource.get().then(responseHandler); + $httpBackend.flush(); + + element = responseHandler.calls.argsFor(0)[0]; + expect(resource.getRestangularUrl()).toEqual('/accounts/123'); + expect(element.getRestangularUrl()).toEqual('/accounts/123'); + }); + it('should use the id from the response, not the request', function () { + var responseHandler = jasmine.createSpy(), element, resource; + $httpBackend.expectGET('/accounts/123').respond({id: 444, name: 'Account 444'}); + resource = Restangular.one('accounts', 123); + resource.get().then(responseHandler); + $httpBackend.flush(); + + element = responseHandler.calls.argsFor(0)[0]; + expect(resource.getRestangularUrl()).toEqual('/accounts/123'); + expect(element.getRestangularUrl()).toEqual('/accounts/444'); + }); + it('should have an empty id in the URL if the response id is empty', function () { + // https://github.com/mgonto/restangular/issues/1421 + var responseHandler = jasmine.createSpy(), element, resource; + $httpBackend.expectGET('/accounts/123').respond({name: 'Account 444'}); + resource = Restangular.one('accounts', 123); + resource.get().then(responseHandler); + $httpBackend.flush(); + + element = responseHandler.calls.argsFor(0)[0]; + expect(resource.getRestangularUrl()).toEqual('/accounts/123'); + expect(element.getRestangularUrl()).toEqual('/accounts'); + }); + it('should return the generated URL for PUTed elements', function () { + var responseHandler = jasmine.createSpy(), element; + $httpBackend.expectPUT('/accounts/123').respond({id: 123, name: 'Account 123'}); + Restangular.one('accounts', 123).put().then(responseHandler); + $httpBackend.flush(); + + element = responseHandler.calls.argsFor(0)[0]; + expect(element.getRestangularUrl()).toEqual('/accounts/123'); + }); + it('should return the generated URL for POSTed elements', function () { + var responseHandler = jasmine.createSpy(), element; + $httpBackend.expectPOST('/accounts').respond({id: 123, name: 'Account 123'}); + Restangular.restangularizeElement(null, {name: 'Account 123'}, 'accounts', false, false).save().then(responseHandler); + $httpBackend.flush(); + + element = responseHandler.calls.argsFor(0)[0]; + expect(element.getRestangularUrl()).toEqual('/accounts/123'); + }); it('should return the generated URL when you chain Restangular methods together', function () { var restangularSpaces = Restangular.one('accounts', 123).one('buildings', 456).all('spaces'); expect(restangularSpaces.getRestangularUrl()).toEqual('/accounts/123/buildings/456/spaces'); }); - }); - describe('getRestangularUrl with useCannonicalId set to true', function () { - it('should return the generated URL when you chain Restangular methods together', function () { - var R = Restangular.withConfig(function (config) { - config.setUseCannonicalId(true); + describe('with useCannonicalId set to true', function () { + it('should return the generated URL when you chain Restangular methods together', function () { + var R = Restangular.withConfig(function (config) { + config.setUseCannonicalId(true); + }); + var restangularSpaces = R.one('accounts', 123).one('buildings', 456).all('spaces'); + expect(restangularSpaces.getRestangularUrl()).toEqual('/accounts/123/buildings/456/spaces'); }); - var restangularSpaces = R.one('accounts', 123).one('buildings', 456).all('spaces'); - expect(restangularSpaces.getRestangularUrl()).toEqual('/accounts/123/buildings/456/spaces'); }); }); - describe('addElementTransformer', function () { it('should allow for a custom method to be placed at the collection level', function () { var accountsPromise; From c4da3b452be8877ac0590ea36259a93e7fb3df01 Mon Sep 17 00:00:00 2001 From: benmag1 Date: Sun, 15 Jan 2017 15:12:49 +0000 Subject: [PATCH 3/6] Adds a Snyk badge to show you are vulnerability-free --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9fd46c61..08b91860 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Build Status](https://travis-ci.org/mgonto/restangular.svg?branch=master)](https://travis-ci.org/mgonto/restangular) [![Coverage Status](https://coveralls.io/repos/github/mgonto/restangular/badge.svg?branch=master)](https://coveralls.io/github/mgonto/restangular?branch=master) [![David](https://img.shields.io/david/dev/mgonto/restangular.svg)](https://david-dm.org/mgonto/restangular/?type=dev) +[![Known Vulnerabilities](https://snyk.io/test/github/mgonto/restangular/badge.svg)](https://snyk.io/test/github/mgonto/restangular) [![PayPayl donate button](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=martin%40gon%2eto&lc=US&item_name=Martin%20Gontovnikas¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted "Donate once-off to this project using Paypal") [![Donate on Gittip](http://img.shields.io/gittip/mgonto.svg)](https://www.gittip.com/mgonto/) From 65f500672094ae2f0c406458111849da5ee0c488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Bostr=C3=B6m?= Date: Wed, 18 Jan 2017 21:40:13 +0200 Subject: [PATCH 4/6] docs(readme): add link to ng2-restangular Closes #1318 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 08b91860..376a0f97 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ -Restangular is an AngularJS service that simplifies common GET, POST, DELETE, and UPDATE requests with a minimum of client code. -It's a perfect fit for any WebApp that consumes data from a RESTful API. +Restangular is an AngularJS service that simplifies common GET, POST, DELETE, and UPDATE requests with a minimum of client code. It's a perfect fit for any WebApp that consumes data from a RESTful API. -Try the [live demo on plunkr](http://plnkr.co/edit/8qrGeE?p=preview). It uses the same example as the official [Angular Javascript Project](http://angularjs.org/#wire-up-a-backend), but with Restangular! +**Note This version of Restangular [only supports Angular 1](#supported-angular-versions). For an Angular 2 version of Restangular, check out [ng2-restangular](https://github.com/2muchcoffeecom/ng2-restangular).** It's a separate project with different maintainers, so issues regarding ng2-restangular should be reported [over there](https://github.com/2muchcoffeecom/ng2-restangular/issues) :wink: + +Learn Restangular! Try the [live demo on plunkr](http://plnkr.co/edit/8qrGeE?p=preview). It uses the same example as the official [Angular Javascript Project](http://angularjs.org/#wire-up-a-backend), but with Restangular! Or watch [a video introduction of a talk I gave at Devoxx France](http://www.parleys.com/play/535a189ee4b0c5ba17d43455/chapter1/about) about Restangular. -Watch [a video introduction of a talk I gave at Devoxx France](http://www.parleys.com/play/535a189ee4b0c5ba17d43455/chapter1/about) about Restangular. #Table of contents From c0d09afcd01f6c507c591932f08c9ad2af8aa520 Mon Sep 17 00:00:00 2001 From: 2muchcoffee Date: Mon, 17 Apr 2017 16:26:29 +0300 Subject: [PATCH 5/6] update readme rename ng2-restangular to ngx-restangular We had to rename ng2-restangular to ngx-restangular due to Angular SemVer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 376a0f97..69a5cc29 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Restangular is an AngularJS service that simplifies common GET, POST, DELETE, and UPDATE requests with a minimum of client code. It's a perfect fit for any WebApp that consumes data from a RESTful API. -**Note This version of Restangular [only supports Angular 1](#supported-angular-versions). For an Angular 2 version of Restangular, check out [ng2-restangular](https://github.com/2muchcoffeecom/ng2-restangular).** It's a separate project with different maintainers, so issues regarding ng2-restangular should be reported [over there](https://github.com/2muchcoffeecom/ng2-restangular/issues) :wink: +**Note This version of Restangular [only supports Angular 1](#supported-angular-versions). For an Angular 2+ version of Restangular, check out [ngx-restangular](https://github.com/2muchcoffeecom/ngx-restangular).** It's a separate project with different maintainers, so issues regarding ngx-restangular should be reported [over there](https://github.com/2muchcoffeecom/ngx-restangular/issues) :wink: Learn Restangular! Try the [live demo on plunkr](http://plnkr.co/edit/8qrGeE?p=preview). It uses the same example as the official [Angular Javascript Project](http://angularjs.org/#wire-up-a-backend), but with Restangular! Or watch [a video introduction of a talk I gave at Devoxx France](http://www.parleys.com/play/535a189ee4b0c5ba17d43455/chapter1/about) about Restangular. From a81d594f12fc88ba4b16e35ff328f6c7fddfb741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Alberto?= Date: Thu, 27 Apr 2017 14:57:00 -0300 Subject: [PATCH 6/6] Docs corrections (#1472) * Anchor correction * Anchor correction --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 69a5cc29..aea15823 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#Restangular +# Restangular [![Build Status](https://travis-ci.org/mgonto/restangular.svg?branch=master)](https://travis-ci.org/mgonto/restangular) [![Coverage Status](https://coveralls.io/repos/github/mgonto/restangular/badge.svg?branch=master)](https://coveralls.io/github/mgonto/restangular?branch=master) @@ -17,7 +17,7 @@ Restangular is an AngularJS service that simplifies common GET, POST, DELETE, an Learn Restangular! Try the [live demo on plunkr](http://plnkr.co/edit/8qrGeE?p=preview). It uses the same example as the official [Angular Javascript Project](http://angularjs.org/#wire-up-a-backend), but with Restangular! Or watch [a video introduction of a talk I gave at Devoxx France](http://www.parleys.com/play/535a189ee4b0c5ba17d43455/chapter1/about) about Restangular. -#Table of contents +# Table of contents - [Restangular](#restangular) - [Differences with $resource](#differences-with-resource) @@ -138,7 +138,7 @@ $scope.user.one('messages', 123).one('from', 123).getList('unread'); **[Back to top](#table-of-contents)** -#How do I add this to my project? +## How do I add this to my project? You can download this by: @@ -155,7 +155,7 @@ You can download this by: **[Back to top](#table-of-contents)** -#Dependencies +## Dependencies Restangular depends on Angular and Lodash (or Underscore). @@ -173,7 +173,7 @@ Each time, there're more Production WebApps using `Restangular`. If your webapp **[Back to top](#table-of-contents)** -#Starter Guide +# Starter Guide ## Quick Configuration (For Lazy Readers) This is all you need to start using all the basic Restangular features.