angularjs-rails-resource 1.0.0.pre.3 → 1.0.0.pre.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f7ce09b68d048977e8091b90cd120e0f7836f183
4
- data.tar.gz: 2c0eb42c1684eb64a5fd58e80a7adc8fed7e4e2f
3
+ metadata.gz: 20771e48c443e10d5168fbd655ef6612531ce5fd
4
+ data.tar.gz: 0f47dfc805d46e310170964e062ca7b343bbbabc
5
5
  SHA512:
6
- metadata.gz: 6eb139ae046e2756eba924f354fbc386d752994ce43bbb67f5696f5c8567cc5ac49a125c7b687079c4766bce508dbd67dbc9c86097647e502daaf00952b01677
7
- data.tar.gz: 56415e2fc32de4a5bd82db9cf0ece3ab680aa583bbb61a5df39bd2f8d14c95a2e74b3028c877da15f6fe648a86f6977937d1be9188d3971a4437d0ba295d3bf3
6
+ metadata.gz: 6fcbd686a622b259875e64033a564ed2291678a7ef439cd83c898fc494b62a81bf7c0a3402f60222d507b51108fe9dfc830b18a9bae7994df3a16eaac3e80c4b
7
+ data.tar.gz: d1508be43ab85c0b47870a55413187d81a4bad5960156cd602c037847dd64b2bd47193f8e8a526b1062109b5146ec1d4a7978ee1dd9eab55178e0fd452900d5f
data/CHANGELOG.md CHANGED
@@ -1,11 +1,22 @@
1
1
  <a name="1.0.0"></a>
2
2
  # 1.0.0
3
+ ## Deprecations
4
+ - <code>requestTransformers</code>, <code>responseInterceptors</code>, <code>afterResponseInterceptors</code> have been replaced with
5
+ a single <code>interceptors</code> chain.
6
+ - <code>beforeRequest</code> - Use <code>interceptBeforeRequestWrapping</code>
7
+ - <code>beforeResponse</code> - Use <code>interceptResponse</code>
8
+ - <code>afterResponse</code> - Use <code>interceptAfterResponse</code>
9
+
3
10
  ## Bug Fixes
4
11
 
5
12
  ## Features
6
13
  - Added <code>configure</code> function to allow changing configuration options after the resource has been initially configured.
7
14
  - Separated out RailsResource into separate service to allow subclassing without using the factories.
8
- - Added snapshot and rollback extension, be sure to check the [README](README.md#serializers) for details.
15
+ - Added mixin capability, see [README](README.md#mixins) for details
16
+ - Added snapshot and rollback extension, see [README](README.md#serializers) for details.
17
+ - Added <code>underscoreParams</code> configuration option to allow turning off parameter underscore renaming.
18
+ - Added <code>fullResponse</code> configuration option to allow returning the full $http response for promise resolution.
19
+ - Added optional query params to class and instance $delete methods
9
20
 
10
21
  ## Breaking Changes
11
22
  - <code>railsResourceFactoryProvider</code> settings have been moved to <code>RailsResourceProvider</code>
@@ -15,8 +26,28 @@
15
26
  - <code>enableRootWrapping</code> was renamed <code>rootWrapping</code>
16
27
  - <code>rootName</code> was renamed <code>name</code>
17
28
  - <code>rootPluralName</code> was renamed <code>pluralName</code>
18
- - Query parameters were not underscored previously. We are now underscoring parameters by default.
19
- The configuration option <code>underscoreParams</code> can be set to false to disable the renaming.
29
+ - Query parameters were not underscored previously. We are now underscoring parameters by default. The configuration option <code>underscoreParams</code> can be set to false to disable the renaming.
30
+ - Replaced <code>railsRootWrappingTransformer</code> and <code>railsRootWrappingInterceptor</code> with <code>railsRootWrapper</code> that has wrap & unwrap methods. This eliminates the need for using promises during resource construction to handle unwrapping data passed into the constructor.
31
+ - Resource constructor no longer executes response interceptors. If you need to customize the constructor you should look at using subclassing instead.
32
+ - <code>processResponse</code>, <code>transformData</code>, <code>callInterceptors</code> have all been removed as part of rewriting the request / response handling.
33
+
34
+ <a name="1.0.0-pre.4"></a>
35
+ # 1.0.0-pre.4
36
+ ## Deprecations
37
+ - <code>requestTransformers</code>, <code>responseInterceptors</code>, <code>afterResponseInterceptors</code> have been replaced with
38
+ a single <code>interceptors</code> chain.
39
+ - <code>beforeRequest</code> - Use <code>interceptBeforeRequestWrapping</code>
40
+ - <code>beforeResponse</code> - Use <code>interceptResponse</code>
41
+ - <code>afterResponse</code> - Use <code>interceptAfterResponse</code>
42
+
43
+ ## Features
44
+ - Added <code>fullResponse</code> configuration option to allow returning the full $http response for promise resolution.
45
+ - Added optional query params to class and instance $delete methods
46
+
47
+ ## Breaking Changes
48
+ - Replaced <code>railsRootWrappingTransformer</code> and <code>railsRootWrappingInterceptor</code> with <code>railsRootWrapper</code> that has wrap & unwrap methods. This eliminates the need for using promises during resource construction to handle unwrapping data passed into the constructor.
49
+ - Resource constructor no longer executes response interceptors. If you need to customize the constructor you should look at using subclassing instead.
50
+ - <code>processResponse</code>, <code>transformData</code>, <code>callInterceptors</code> have all been removed as part of rewriting the request / response handling.
20
51
 
21
52
  <a name="1.0.0-pre.3"></a>
22
53
  # 1.0.0-pre.3
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  A resource factory inspired by $resource from AngularJS and [Misko's recommendation](http://stackoverflow.com/questions/11850025/recommended-way-of-getting-data-from-the-server).
5
5
 
6
6
  ## Differences from $resource
7
- This library is not a drop in replacement for $resource. There are significant differences that you should be aware of and
7
+ This library is not a drop in replacement for $resource. There are significant differences that you should be aware of:
8
8
 
9
9
  1. <code>get</code> and <code>query</code> return [$q promises](http://docs.angularjs.org/api/ng.$q), not an instance or array that will be populated. To gain access to the results you
10
10
  should use the promise <code>then</code> function.
@@ -205,7 +205,12 @@ defined on the resource can be called multiple times to adjust properties as nee
205
205
  * **underscoreParams** *(optional)* - Controls whether or not query parameters are converted from camel case to underscore.
206
206
  * **updateMethod** *(optional)* - Allows overriding the default HTTP method (PUT) used for update. Valid values are "post", "put", or "patch".
207
207
  * **serializer** *(optional)* - Allows specifying a custom [serializer](#serializers) to configure custom serialization options.
208
- * **requestTransformers** *(optional) - See [Transformers / Interceptors](#transformers--interceptors)
208
+ * **fullResponse** *(optional)* - When set to true promises will return full $http responses instead of just the response data.
209
+ * **interceptors** *(optional)* - See [Interceptors](#interceptors)
210
+ * **extensions** *(optional)* - See [Extensions](#extensions)
211
+
212
+ **Deprecated:**
213
+ * **requestTransformers** *(optional)* - See [Transformers / Interceptors](#transformers--interceptors)
209
214
  * **responseInterceptors** *(optional)* - See [Transformers / Interceptors](#transformers--interceptors)
210
215
  * **afterResponseInterceptors** *(optional)* - See [Transformers / Interceptors](#transformers--interceptors)
211
216
 
@@ -222,6 +227,8 @@ Each configuration option listed is exposed as a method on the provider that tak
222
227
  * defaultParams - {function(object):RailsResourceProvider}
223
228
  * underscoreParams - {function(boolean):RailsResourceProvider}
224
229
  * updateMethod - {function(boolean):RailsResourceProvider}
230
+ * fullResponse - {function(boolean):RailsResourceProvider}
231
+ * extensions - {function(...string):RailsResourceProvider}
225
232
 
226
233
  For example, to turn off the root wrapping application-wide and set the update method to PATCH:
227
234
 
@@ -295,18 +302,39 @@ RailsResources have the following class methods available.
295
302
  * **data** {object} - The data to serialize and POST / PUT / PATCH
296
303
  * **returns** {promise} A promise that will be resolved with a new Resource instance (or instances in the case of an array response).
297
304
 
298
- * $delete(customUrl) - Executes a DELETE to a custom URL. The main difference between this and $http.delete is that a server response that contains a body will be deserialized using the normal Resource deserialization process.
305
+ * $delete(customUrl, queryParams) - Executes a DELETE to a custom URL. The main difference between this and $http.delete is that a server response that contains a body will be deserialized using the normal Resource deserialization process.
299
306
  * **customUrl** {string} - The url to DELETE to
307
+ * **queryParams** {object} (optional) - The set of query parameters to include in the DELETE request
300
308
  * **returns** {promise} A promise that will be resolved with a new Resource instance (or instances in the case of an array response) if the server includes a response body.
301
309
 
302
- * beforeRequest(fn(data, resource)) - See [Transformers](#transformers) for more information. The function is called prior to the serialization process so the data
310
+ * $http(httpConfig, context, resourceConfigOverrides) - Executes an HTTP operation specified by the config. The request data is serialized and root wrapped (if configured). The response data is unwrapped (if configured) and deserialized and copied to the context object if specified.
311
+ * **httpConfig** {object} - Standard $http config object.
312
+ * **context** {object} - The instance that the operation is being run against.
313
+ * **resourceConfigOverrides** {object} - An optional set of RailsResource configuration option overrides to use for this request.
314
+
315
+ * addInterceptor(interceptor) - Adds an interceptor to the resource class.
316
+ * **interceptor** {object | string} - See [Interceptors](#interceptors) for details of object format.
317
+
318
+ * intercept(phase, callback) - Creates an interceptor for the specified phase and adds it to the resource's interceptor list. The callback function will be executed when the interceptor phase is run. If the callback function returns a value that will take the place of the value going forward in the promise chain.
319
+ * **phase** {string} - The interceptor phase, see [Interceptors](#interceptors) for a list of phases.
320
+ * **callback** {function(value, resourceConstructor, context)} - The callback function to execute. The value parameter varies based on the phase. See [Interceptors](#interceptors) for details. The resourceConstructor is the resource's constructor function. The context is the resource instance that operation is running against which may be undefined.
321
+ * interceptBeforeRequest(callback) - Shortcut for intercept('beforeRequest', callback)
322
+ * interceptBeforeRequestWrapping(callback) - Shortcut for intercept('beforeRequestWrapping', callback)
323
+ * interceptRequest(callback) - Shortcut for intercept('request', callback)
324
+ * interceptBeforeResponse(callback) - Shortcut for intercept('beforeResponse', callback)
325
+ * interceptBeforeResponseDeserialize(callback) - Shortcut for intercept('beforeResponseDeserialize', callback)
326
+ * interceptResponse - Shortcut for intercept('response', callback)
327
+ * interceptAfterResponse - Shortcut for intercept('afterResponse', callback)
328
+
329
+ **Deprecated**
330
+ * beforeRequest(fn(data, resource)) - See [Interceptors](#interceptors) for more information. The function is called prior to the serialization process so the data
303
331
  passed to the function is still a Resource instance as long as another transformation function has not returned a new object to serialize.
304
332
  * fn(data, resource) {function} - The function to add as a transformer.
305
333
  * **data** {object} - The data being serialized
306
334
  * **resource** {Resource class} - The Resource class that is calling the function
307
335
  * **returns** {object | undefined} - If the function returns a new object that object will instead be used for serialization.
308
336
 
309
- * beforeResponse(fn(data, resource, context)) - See [Interceptors](#interceptors) for more information. The function is called after the response data has been deserialized.
337
+ * beforeResponse(fn(data, resource, context)) - See [Interceptors](#interceptors) for more information. The function is called after the response data has been unwrapped and deserialized.
310
338
  * fn(data, resource, context) {function} - The function to add as an interceptor
311
339
  * **data** {object} - The data received from the server
312
340
  * **resource** {Resource function} - The Resource constructor that is calling the function
@@ -335,12 +363,15 @@ All of the instance methods will update the instance in-place on response and wi
335
363
  * remove(), delete() - Executes an HTTP DELETE against the resource's URL (e.g. /books/1234)
336
364
  * **returns** {promise} - A promise that will be resolved with the instance itself
337
365
 
366
+ * $http(httpConfig, resourceConfigOverrides) - Executes class method $http with the resource instance as the operation context.
367
+
338
368
  * $post(customUrl), $put(customUrl), $patch(customUrl) - Serializes and submits the instance using an HTTP POST/PUT/PATCH to the given URL.
339
369
  * **customUrl** {string} - The url to POST / PUT / PATCH to
340
370
  * **returns** {promise} - A promise that will be resolved with the instance itself
341
371
 
342
- * $delete(customUrl) - Executes a DELETE to a custom URL. The main difference between this and $http.delete is that a server response that contains a body will be deserialized using the normal Resource deserialization process.
372
+ * $delete(customUrl, queryParams) - Executes a DELETE to a custom URL. The main difference between this and $http.delete is that a server response that contains a body will be deserialized using the normal Resource deserialization process.
343
373
  * **customUrl** {string} - The url to DELETE to
374
+ * **queryParams** {object} (optional) - The set of query parameters to include in the DELETE request
344
375
  * **returns** {promise} - A promise that will be resolved with the instance itself
345
376
 
346
377
 
@@ -417,8 +448,68 @@ The customizer function passed to the railsSerializer has available to it the fo
417
448
  The serializers are defined using mostly instance prototype methods. For information on those methods please see the inline documentation. There are however a couple of class methods that
418
449
  are also defined to expose underscore, camelize, and pluralize. Those functions are set to the value specified by the configuration options sent to the serializer.
419
450
 
451
+ ## Interceptors
452
+ The entire request / response processing is configured as a [$q promise chain](http://docs.angularjs.org/api/ng.$q). Interceptors allow inserting additional synchronous or asynchronous processing at various phases in the request / response cycle. The flexibility of the synchronous or asynchronous promise resolution allows any number of customizations to be built. For instance, on response you could load additional data before returning that the current response is complete. Or, you could listen to multiple phases and set a flag that a save operation is in progress in <code>beforeRequest</code> and then in <code>afterResponse</code> and <code>afterResponseError</code> you could clear the flag.
453
+
454
+ Interceptors are similar in design to the $http interceptors. You can add interceptors via the <code>RailsResource.addInterceptors</code> method or by explicitly adding them to the <code>interceptors</code> array on the on the resource <code>config</code> object. When you add the interceptor, you can add it using either the interceptor service factory name or the object reference. An interceptor should contain a set of keys representing one of the valid phases and the callback function for the phase.
455
+
456
+ There are several phases for both request and response to give users and mixins more flexibility for exactly where they want to insert a customization. Each phase also has a corresponding error phase which is the phase name appended with Error (e.g. beforeResponse and beforeResponseError). The error phases receive the current rejection value which in most cases would be the error returned from $http. Since these are $q promises, your interceptor can decide whether or not to propagate the error or recover from it. If you want to propagate the error, you must return a <code>$q.reject(reason)</code> result. Otherwise any value you return will be treated as a successful value to use for the rest of the chain. For instance, in the <code>beforeResponseError</code> phase you could attempt to recover by using an alternate URL for the request data and return the new promise as the result.
457
+
458
+ Each request phase interceptor is called with the $http config object, the resource constructor, and if applicable the resource instance. The interceptor is free to modify the config or create a new one. The interceptor function must return a valid $http config or a promise that will eventually resolve to a config object.
459
+
460
+ The valid request phases are:
461
+
462
+ * beforeRequest: Interceptors are called prior to any data serialization or root wrapping.
463
+ * beforeRequestError: Interceptors get called when a previous interceptor threw an error or resolved with a rejection.
464
+ * beforeRequestWrapping: Interceptors are called after data serialization but before root wrapping.
465
+ * beforeRequestWrappingError: Interceptors get called when a previous interceptor threw an error or resolved with a rejection.
466
+ * request: Interceptors are called after any data serialization and root wrapping have been performed.
467
+ * requestError: Interceptors get called when a previous interceptor threw an error or resolved with a rejection.
420
468
 
421
- ## Transformers / Interceptors
469
+ The beforeResponse and response interceptors are called with the $http response object, the resource constructor, and if applicable the resource instance. The afterResponse interceptors are typically called with the response data instead of the full response object unless the config option fullResponse has been set to true. Like the request interceptor callbacks the response callbacks can manipulate the data or return new data. The interceptor function must return
470
+
471
+ The valid response phases are:
472
+
473
+ * beforeResponse: Interceptors are called prior to any data processing.
474
+ * beforeResponseError: Interceptors get called when a previous interceptor threw an error or resolved with a rejection.
475
+ * beforeResponseDeserialize: Interceptors are called after root unwrapping but prior to data deserializing.
476
+ * beforeResponseDeserializeError: Interceptors get called when a previous interceptor threw an error or resolved with a rejection.
477
+ * response: Interceptors are called after the data has been deserialized and root unwrapped but prior to the data being copied to the resource instance if applicable.
478
+ * responseError: Interceptors get called when a previous interceptor threw an error or resolved with a rejection.
479
+ * afterResponse: Interceptors are called at the very end of the response chain after all processing
480
+ has been completed. The value of the first parameter is one of the following:
481
+ - resource instance: When fullResponse is false and the operation was called on a resource instance.
482
+ - response data: When fullResponse is false and the operation was called on the resource class.
483
+ - $http response: When fullResponse is true
484
+ * afterResponseError: Interceptors get called when a previous interceptor threw an error or resolved with a rejection.
485
+
486
+ ### Example Interceptor
487
+ ```javascript
488
+ angular.module('rails').factory('saveIndicatorInterceptor', function () {
489
+ return {
490
+ 'beforeRequest': function (httpConfig, resourceConstructor, context) {
491
+ if (context && (httpConfig.method === 'post' || httpConfig.method === 'put')) {
492
+ context.savePending = true;
493
+ }
494
+ return httpConfig;
495
+ },
496
+ 'afterResponse': function (result, resourceConstructor, context) {
497
+ if (context) {
498
+ context.savePending = false;
499
+ }
500
+ return result;
501
+ },
502
+ 'afterResponseError': function (rejection, resourceConstructor, context) {
503
+ if (context) {
504
+ context.savePending = false;
505
+ }
506
+ return $q.reject(rejection);
507
+ }
508
+ };
509
+ });
510
+ ```
511
+
512
+ ## Transformers / Interceptors (**DEPRECATED**)
422
513
  The transformers and interceptors can be specified using an array containing transformer/interceptor functions or strings
423
514
  that can be resolved using Angular's DI. The transformers / interceptors concept was prior to the [serializers](#serializers) but
424
515
  we kept the API available because there may be use cases that can be accomplished with these but not the serializers.
data/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "angularjs-rails-resource",
3
- "version": "1.0.0-pre.3",
3
+ "version": "1.0.0-pre.4",
4
4
  "main": "angularjs-rails-resource.js",
5
5
  "description": "A resource factory inspired by $resource from AngularJS",
6
6
  "repository": {
data/changelog.js CHANGED
@@ -142,7 +142,7 @@ var writeChangelog = function(stream, commits, version) {
142
142
  fix: {},
143
143
  feat: {},
144
144
  perf: {},
145
- deprecate: {},
145
+ deprecates: {},
146
146
  breaks: {}
147
147
  };
148
148
 
@@ -157,6 +157,15 @@ var writeChangelog = function(stream, commits, version) {
157
157
  section[component].push(commit);
158
158
  }
159
159
 
160
+ if (commit.deprecates) {
161
+ sections.deprecates[component] = sections.deprecates[component] || [];
162
+ commit.deprecates.forEach(function (deprecation) {
163
+ sections.deprecates[component].push({
164
+ subject: deprecation
165
+ });
166
+ });
167
+ }
168
+
160
169
  if (commit.breaking) {
161
170
  sections.breaks[component] = sections.breaks[component] || [];
162
171
  sections.breaks[component].push({
@@ -1,7 +1,7 @@
1
1
  module Angularjs
2
2
  module Rails
3
3
  module Resource
4
- VERSION = '1.0.0.pre.3'
4
+ VERSION = '1.0.0.pre.4'
5
5
  end
6
6
  end
7
7
  end
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "angularjs-rails-resource",
3
3
  "description" : "A resource factory inspired by $resource from AngularJS",
4
- "version": "1.0.0-pre.3",
4
+ "version": "1.0.0-pre.4",
5
5
  "main" : "dist/angularjs-rails-resource.min.js",
6
6
  "homepage" : "https://github.com/FineLinePrototyping/angularjs-rails-resource.git",
7
7
  "author" : "",
@@ -175,8 +175,6 @@ describe('RailsResource.snapshots', function () {
175
175
  book.rollback();
176
176
 
177
177
  expect(book.$key).toBe('1235');
178
- expect(book.$snapshots).toBeDefined();
179
- expect(book.$snapshots.length).toBe(0);
180
178
  });
181
179
 
182
180
  it('should roll back to the first snapshot for -1', function () {
@@ -1,6 +1,7 @@
1
- describe('transformers', function () {
1
+ describe('interceptors', function () {
2
2
  'use strict';
3
- var $httpBackend, $rootScope, factory, Test, testInterceptor, testAfterInterceptor,
3
+ var $q, $http, $httpBackend, $rootScope, factory, Test, testInterceptor, testAfterInterceptor, testRequestTransformer,
4
+ deprecatedTestInterceptor, deprecatedTestAfterInterceptor,
4
5
  config = {
5
6
  url: '/test',
6
7
  name: 'test'
@@ -9,7 +10,7 @@ describe('transformers', function () {
9
10
  beforeEach(function () {
10
11
  module('rails');
11
12
 
12
- angular.module('rails').factory('railsTestInterceptor', function () {
13
+ angular.module('rails').factory('deprecatedRailsTestInterceptor', function () {
13
14
  return function (promise) {
14
15
  return promise.then(function (response) {
15
16
  response.data.interceptorAdded = 'x';
@@ -18,7 +19,7 @@ describe('transformers', function () {
18
19
  }
19
20
  });
20
21
 
21
- angular.module('rails').factory('railsTestAfterInterceptor', function () {
22
+ angular.module('rails').factory('deprecatedRailsTestAfterInterceptor', function () {
22
23
  return function (promise) {
23
24
  return promise.then(function (resource) {
24
25
  resource.interceptorAdded = 'x';
@@ -26,15 +27,88 @@ describe('transformers', function () {
26
27
  });
27
28
  }
28
29
  });
30
+
31
+ angular.module('rails').factory('railsTestInterceptor', function () {
32
+ return {
33
+ 'response': function (response) {
34
+ response.data.interceptorAdded = 'x';
35
+ return response;
36
+ },
37
+ 'responseError': function (rejection) {
38
+ rejection.interceptorCalled = true;
39
+ return $q.reject(rejection);
40
+ }
41
+ };
42
+ });
43
+
44
+ angular.module('rails').factory('asyncInterceptor', function () {
45
+ return {
46
+ 'response': function (response) {
47
+ return $http.get('/async').then(function (asyncResponse) {
48
+ response.data.async = asyncResponse.data;
49
+ return response;
50
+ });
51
+ }
52
+ };
53
+ });
54
+
55
+ angular.module('rails').factory('saveIndicatorInterceptor', function () {
56
+ return {
57
+ 'beforeRequest': function (httpConfig, resourceConstructor, context) {
58
+ if (context && (httpConfig.method === 'put' || httpConfig.method === 'post')) {
59
+ context.$savePending = true;
60
+ }
61
+ return httpConfig;
62
+ },
63
+ 'afterResponse': function (result, resourceConstructor, context) {
64
+ if (context) {
65
+ context.$savePending = false;
66
+ }
67
+ return result;
68
+ },
69
+ 'afterResponseError': function (rejection, resourceConstructor, context) {
70
+ if (context) {
71
+ context.$savePending = false;
72
+ }
73
+ return $q.reject(rejection);
74
+ }
75
+ };
76
+ });
77
+
78
+ angular.module('rails').factory('railsTestAfterInterceptor', function () {
79
+ return {
80
+ 'afterResponse': function (response) {
81
+ response.interceptorAdded = 'x';
82
+ return response;
83
+ }
84
+ };
85
+ });
86
+
87
+ angular.module('rails').factory('railsTestRequestTransformer', function () {
88
+ return {
89
+ 'beforeRequest': function (httpConfig, resource) {
90
+ httpConfig.data.transformer_called = true;
91
+ return httpConfig;
92
+ }
93
+ };
94
+ });
95
+
29
96
  });
30
97
 
31
- beforeEach(inject(function (_$httpBackend_, _$rootScope_, railsResourceFactory, railsTestInterceptor, railsTestAfterInterceptor) {
98
+ beforeEach(inject(function (_$q_, _$http_, _$httpBackend_, _$rootScope_, railsResourceFactory,
99
+ railsTestInterceptor, railsTestAfterInterceptor, railsTestRequestTransformer,
100
+ deprecatedRailsTestInterceptor, deprecatedRailsTestAfterInterceptor) {
101
+ $q = _$q_;
102
+ $http = _$http_;
32
103
  $httpBackend = _$httpBackend_;
33
104
  $rootScope = _$rootScope_;
34
105
  factory = railsResourceFactory;
35
106
  Test = railsResourceFactory(config);
36
107
  testInterceptor = railsTestInterceptor;
37
108
  testAfterInterceptor = railsTestAfterInterceptor;
109
+ deprecatedTestInterceptor = deprecatedRailsTestInterceptor;
110
+ deprecatedTestAfterInterceptor = deprecatedRailsTestAfterInterceptor;
111
+ testRequestTransformer = railsTestRequestTransformer;
38
112
  }));
39
113
 
40
114
  afterEach(function () {
@@ -42,14 +116,14 @@ describe('transformers', function () {
42
116
  $httpBackend.verifyNoOutstandingRequest();
43
117
  });
44
118
 
45
- describe('before response', function () {
119
+ describe('deprecated before response', function () {
46
120
  it('should be able to reference interceptor using name', function () {
47
121
  var promise, result, Resource, testConfig = {};
48
122
 
49
123
  $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
50
124
 
51
125
  angular.copy(config, testConfig);
52
- testConfig.responseInterceptors = ['railsTestInterceptor'];
126
+ testConfig.responseInterceptors = ['deprecatedRailsTestInterceptor'];
53
127
  Resource = factory(testConfig);
54
128
 
55
129
  expect(promise = Resource.get(123)).toBeDefined();
@@ -71,7 +145,7 @@ describe('transformers', function () {
71
145
 
72
146
 
73
147
  angular.copy(config, testConfig);
74
- testConfig.responseInterceptors = [testInterceptor];
148
+ testConfig.responseInterceptors = [deprecatedTestInterceptor];
75
149
  Resource = factory(testConfig);
76
150
 
77
151
  expect(promise = Resource.get(123)).toBeDefined();
@@ -138,15 +212,15 @@ describe('transformers', function () {
138
212
  });
139
213
  });
140
214
 
141
- describe('after response', function () {
215
+ describe('response', function () {
142
216
  it('should be able to reference interceptor using name', function () {
143
217
  var promise, result, Resource, testConfig = {};
144
218
 
145
219
  $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
146
220
 
147
221
  angular.copy(config, testConfig);
148
- testConfig.afterResponseInterceptors = ['railsTestAfterInterceptor'];
149
222
  Resource = factory(testConfig);
223
+ Resource.addInterceptor('railsTestInterceptor');
150
224
 
151
225
  expect(promise = Resource.get(123)).toBeDefined();
152
226
 
@@ -165,9 +239,130 @@ describe('transformers', function () {
165
239
 
166
240
  $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
167
241
 
242
+ angular.copy(config, testConfig);
243
+ Resource = factory(testConfig);
244
+ Resource.addInterceptor(testInterceptor);
245
+
246
+ expect(promise = Resource.get(123)).toBeDefined();
247
+
248
+ promise.then(function (response) {
249
+ result = response;
250
+ });
251
+
252
+ $httpBackend.flush();
253
+
254
+ expect(result).toBeInstanceOf(Resource);
255
+ expect(result).toEqualData({interceptorAdded: 'x', id: 123, abcDef: 'xyz'});
256
+ });
257
+
258
+ it('should execute error interceptors on HTTP error', function () {
259
+ var promise, result, rejection, Resource, testConfig = {};
260
+
261
+ $httpBackend.expectGET('/test/123').respond(500);
168
262
 
169
263
  angular.copy(config, testConfig);
170
- testConfig.afterResponseInterceptors = [testAfterInterceptor];
264
+ Resource = factory(testConfig);
265
+ Resource.addInterceptor(testInterceptor);
266
+
267
+ expect(promise = Resource.get(123)).toBeDefined();
268
+
269
+ promise.then(function (response) {
270
+ result = response;
271
+ }, function (error) {
272
+ rejection = error;
273
+ });
274
+
275
+ $httpBackend.flush();
276
+
277
+ expect(result).not.toBeDefined();
278
+ expect(rejection).toBeDefined();
279
+ expect(rejection.interceptorCalled).toBeTruthy();
280
+ });
281
+
282
+ it('should be able to add interceptor using interceptResponse', function () {
283
+ var promise, result, Resource, interceptorCalled = false;
284
+
285
+ $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
286
+
287
+ Resource = factory(config);
288
+
289
+ Resource.interceptResponse(function (response, constructor, context) {
290
+ expect(response.data).toEqualData({id: 123, abcDef: 'xyz'});
291
+ expect(constructor).toEqual(Resource);
292
+ expect(context).toBeUndefined();
293
+ interceptorCalled = true;
294
+ return response;
295
+ });
296
+
297
+ expect(promise = Resource.get(123)).toBeDefined();
298
+
299
+ promise.then(function (response) {
300
+ result = response;
301
+ });
302
+
303
+ $httpBackend.flush();
304
+
305
+ expect(result).toBeInstanceOf(Resource);
306
+ expect(result).toEqualData({id: 123, abcDef: 'xyz'});
307
+ expect(interceptorCalled).toBeTruthy();
308
+ });
309
+
310
+ it('should set context to resource instance', function () {
311
+ var instance, Resource, interceptorCalled = false;
312
+
313
+ $httpBackend.expectPOST('/test').respond(200, {id: 123, abc_def: 'xyz'});
314
+
315
+ Resource = factory(config);
316
+
317
+ instance = new Resource({abcDef: 'xyz'});
318
+
319
+ Resource.interceptResponse(function (response, constructor, context) {
320
+ expect(response.data).toEqualData({id: 123, abcDef: 'xyz'});
321
+ expect(constructor).toEqual(Resource);
322
+ expect(context).toBeInstanceOf(Resource);
323
+ expect(context).toEqualData(instance);
324
+ interceptorCalled = true;
325
+ return response;
326
+ });
327
+
328
+ instance.save();
329
+
330
+ $httpBackend.flush();
331
+
332
+ expect(interceptorCalled).toBeTruthy();
333
+ });
334
+ });
335
+
336
+ describe('deprecated after response', function () {
337
+ it('should be able to reference interceptor using name', function () {
338
+ var promise, result, Resource, testConfig = {};
339
+
340
+ $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
341
+
342
+ angular.copy(config, testConfig);
343
+ testConfig.afterResponseInterceptors = ['deprecatedRailsTestAfterInterceptor'];
344
+ Resource = factory(testConfig);
345
+
346
+ expect(promise = Resource.get(123)).toBeDefined();
347
+
348
+ promise.then(function (response) {
349
+ result = response;
350
+ });
351
+
352
+ $httpBackend.flush();
353
+
354
+ expect(result).toBeInstanceOf(Resource);
355
+ expect(result).toEqualData({interceptorAdded: 'x', id: 123, abcDef: 'xyz'});
356
+ });
357
+
358
+ it('should be able to add interceptor using reference', function () {
359
+ var promise, result, Resource, testConfig = {};
360
+
361
+ $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
362
+
363
+
364
+ angular.copy(config, testConfig);
365
+ testConfig.afterResponseInterceptors = [deprecatedTestAfterInterceptor];
171
366
  Resource = factory(testConfig);
172
367
 
173
368
  expect(promise = Resource.get(123)).toBeDefined();
@@ -231,5 +426,212 @@ describe('transformers', function () {
231
426
  });
232
427
  });
233
428
 
429
+ describe('after response', function () {
430
+ it('should be able to reference interceptor using name', function () {
431
+ var promise, result, Resource, testConfig = {};
432
+
433
+ $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
434
+
435
+ angular.copy(config, testConfig);
436
+ testConfig.interceptors = ['railsTestAfterInterceptor'];
437
+ Resource = factory(testConfig);
438
+
439
+ expect(promise = Resource.get(123)).toBeDefined();
440
+
441
+ promise.then(function (response) {
442
+ result = response;
443
+ });
444
+
445
+ $httpBackend.flush();
446
+
447
+ expect(result).toBeInstanceOf(Resource);
448
+ expect(result).toEqualData({interceptorAdded: 'x', id: 123, abcDef: 'xyz'});
449
+ });
450
+
451
+ it('should be able to add interceptor using reference', function () {
452
+ var promise, result, Resource, testConfig = {};
453
+
454
+ $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
455
+
456
+ angular.copy(config, testConfig);
457
+ testConfig.interceptors = [testAfterInterceptor];
458
+ Resource = factory(testConfig);
459
+
460
+ expect(promise = Resource.get(123)).toBeDefined();
461
+
462
+ promise.then(function (response) {
463
+ result = response;
464
+ });
465
+
466
+ $httpBackend.flush();
467
+
468
+ expect(result).toBeInstanceOf(Resource);
469
+ expect(result).toEqualData({interceptorAdded: 'x', id: 123, abcDef: 'xyz'});
470
+ });
471
+
472
+ it('should be able to add interceptor using afterResponse', function () {
473
+ var promise, result, Resource, interceptorCalled = false;
474
+
475
+ $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
476
+
477
+ Resource = factory(config);
478
+
479
+ Resource.interceptAfterResponse(function (resource, constructor, context) {
480
+ expect(resource).toEqualData({id: 123, abcDef: 'xyz'});
481
+ expect(constructor).toEqual(Resource);
482
+ interceptorCalled = true;
483
+ });
484
+
485
+ expect(promise = Resource.get(123)).toBeDefined();
486
+
487
+ promise.then(function (response) {
488
+ result = response;
489
+ });
490
+
491
+ $httpBackend.flush();
492
+
493
+ expect(result).toBeInstanceOf(Resource);
494
+ expect(result).toEqualData({id: 123, abcDef: 'xyz'});
495
+ expect(interceptorCalled).toBeTruthy();
496
+ });
497
+
498
+ it('should set context to resource instance', function () {
499
+ var instance, Resource, interceptorCalled = false;
500
+
501
+ $httpBackend.expectPOST('/test').respond(200, {id: 123, abc_def: 'xyz'});
502
+
503
+ Resource = factory(config);
504
+
505
+ instance = new Resource({abcDef: 'xyz'});
506
+
507
+ Resource.interceptAfterResponse(function (resource, constructor, context) {
508
+ expect(resource).toEqualData({id: 123, abcDef: 'xyz'});
509
+ expect(constructor).toEqual(Resource);
510
+ interceptorCalled = true;
511
+ });
512
+
513
+ instance.save();
514
+
515
+ $httpBackend.flush();
516
+
517
+ expect(interceptorCalled).toBeTruthy();
518
+ });
519
+ });
520
+
521
+ describe('before request wrapping', function () {
522
+ it('should be able to add transformer using name', function() {
523
+ var Resource, testConfig = {};
524
+
525
+ $httpBackend.expectPOST('/test/123', {test: {id: 123, transformer_called: true}}).respond(200, {id: 123, abc_def: 'xyz'});
526
+
527
+ angular.copy(config, testConfig);
528
+ testConfig.interceptors = ['railsTestRequestTransformer'];
529
+ Resource = factory(testConfig);
530
+ new Resource({id: 123}).create();
531
+
532
+ $httpBackend.flush();
533
+ });
534
+
535
+ it('should be able to add transformer using reference', function() {
536
+ var Resource, testConfig = {};
537
+
538
+ $httpBackend.expectPOST('/test/123', {test: {id: 123, transformer_called: true}}).respond(200, {id: 123, abc_def: 'xyz'});
539
+
540
+ angular.copy(config, testConfig);
541
+ testConfig.interceptors = [testRequestTransformer];
542
+ Resource = factory(testConfig);
543
+ new Resource({id: 123}).create();
544
+
545
+ $httpBackend.flush();
546
+ });
547
+
548
+ it('should call transformer function with beforeRequest', function () {
549
+ var Resource, transformerCalled = false;
550
+
551
+ $httpBackend.expectPOST('/test/123', {test: {id: 123}}).respond(200, {id: 123, abc_def: 'xyz'});
552
+
553
+ Resource = factory(config);
554
+ Resource.interceptBeforeRequest(function (httpConfig, constructor) {
555
+ expect(httpConfig.data).toEqualData({id: 123});
556
+ expect(constructor).toEqual(Resource);
557
+ transformerCalled = true;
558
+ return httpConfig;
559
+ });
560
+
561
+ new Resource({id: 123}).create();
562
+
563
+ $httpBackend.flush();
564
+ expect(transformerCalled).toBeTruthy();
565
+ });
566
+
567
+ it('should be able to return new data from beforeRequest function', function () {
568
+ var Resource, transformerCalled = false;
569
+
570
+ $httpBackend.expectPOST('/test/123', {test: {id: 1}}).respond(200, {id: 123, abc_def: 'xyz'});
571
+
572
+ Resource = factory(config);
573
+ Resource.interceptBeforeRequest(function (httpConfig, resource) {
574
+ expect(httpConfig.data).toEqualData({id: 123});
575
+ expect(resource).toEqual(Resource);
576
+ transformerCalled = true;
577
+ httpConfig.data = {id: 1};
578
+ return httpConfig;
579
+ });
580
+
581
+ new Resource({id: 123}).create();
582
+
583
+ $httpBackend.flush();
584
+ expect(transformerCalled).toBeTruthy();
585
+ });
586
+ });
587
+
588
+ describe('async interceptor', function () {
589
+ it('should execute both requests', function () {
590
+ var testResult;
591
+
592
+ $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
593
+ $httpBackend.expectGET('/async').respond(200, {id: 1, value: true});
594
+
595
+ Test.addInterceptor('asyncInterceptor');
596
+ Test.get(123).then(function (result) {
597
+ testResult = result;
598
+ });
234
599
 
600
+ $httpBackend.flush();
601
+ expect(testResult).toEqualData({id: 123, abcDef: 'xyz', async: {id: 1, value: true}});
602
+ });
603
+
604
+ it('should fail if async operation fails', function () {
605
+ var testResult, testError;
606
+
607
+ $httpBackend.expectGET('/test/123').respond(200, {id: 123, abc_def: 'xyz'});
608
+ $httpBackend.expectGET('/async').respond(500);
609
+
610
+ Test.addInterceptor('asyncInterceptor');
611
+ Test.get(123).then(function (result) {
612
+ testResult = result;
613
+ }, function (error) {
614
+ testError = error;
615
+ });
616
+
617
+ $httpBackend.flush();
618
+ expect(testResult).not.toBeDefined();
619
+ expect(testError).toBeDefined();
620
+ });
621
+ });
622
+
623
+ describe('multi-phase interceptor', function () {
624
+ it('should execute multiple success phases', function () {
625
+ var test = new Test({abcDef: 'xyz'});
626
+
627
+ Test.addInterceptor('saveIndicatorInterceptor');
628
+ $httpBackend.expectPOST('/test', {test: {abc_def: 'xyz'}}).respond(200, {id: 123, abc_def: 'xyz'});
629
+ $rootScope.$apply(function () {
630
+ test.save();
631
+ });
632
+ expect(test.$savePending).toEqual(true);
633
+ $httpBackend.flush();
634
+ expect(test.$savePending).toEqual(false);
635
+ });
636
+ });
235
637
  });