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 +4 -4
- data/CHANGELOG.md +34 -3
- data/README.md +98 -7
- data/bower.json +1 -1
- data/changelog.js +10 -1
- data/lib/angularjs-rails-resource/version.rb +1 -1
- data/package.json +1 -1
- data/test/unit/angularjs/rails/extensions/snapshotsSpec.js +0 -2
- data/test/unit/angularjs/rails/interceptorsSpec.js +413 -11
- data/test/unit/angularjs/rails/resourceSpec.js +19 -0
- data/test/unit/angularjs/rails/rootWrappingSpec.js +9 -24
- data/test/unit/angularjs/rails/transformersSpec.js +1 -2
- data/vendor/assets/javascripts/angularjs/rails/resource/extensions/snapshots.js +7 -4
- data/vendor/assets/javascripts/angularjs/rails/resource/resource.js +351 -115
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20771e48c443e10d5168fbd655ef6612531ce5fd
|
4
|
+
data.tar.gz: 0f47dfc805d46e310170964e062ca7b343bbbabc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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
|
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
|
-
* **
|
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
|
-
*
|
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
|
-
|
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
data/changelog.js
CHANGED
@@ -142,7 +142,7 @@ var writeChangelog = function(stream, commits, version) {
|
|
142
142
|
fix: {},
|
143
143
|
feat: {},
|
144
144
|
perf: {},
|
145
|
-
|
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({
|
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.
|
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('
|
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('
|
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('
|
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,
|
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 = ['
|
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 = [
|
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('
|
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
|
-
|
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
|
});
|