Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit be17c58

Browse files
committedNov 8, 2014
Finished $http fallback.
1 parent 38d482f commit be17c58

28 files changed

+3547
-303
lines changed
 

‎CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
###### Other
77
- #199 - Re-implement bindOne & bindAll in js-data-angular (they're missing from js-data)
88
- #200 - Need to properly trigger digest where angular-data would have before
9+
- Added DSHttpAdapter fallback that uses $http if js-data-http isn't loaded
910

1011
##### 1.0.0 - 04 October 2014
1112

‎Gruntfile.js

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ module.exports = function (grunt) {
3535
main: {
3636
options: {
3737
banner: '/**\n' +
38-
'* @author Jason Dobry <jason.dobry@gmail.com>\n' +
39-
'* @file js-data-angular.min.js\n' +
40-
'* @version <%= pkg.version %> - Homepage <https://www.js-data.io/js-data-angular/>\n' +
41-
'* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>\n' +
42-
'* @license MIT <https://github.com/js-data/js-data-angular/blob/master/LICENSE>\n' +
43-
'*\n' +
44-
'* @overview Angular wrapper for js-data.\n' +
45-
'*/\n'
38+
'* @author Jason Dobry <jason.dobry@gmail.com>\n' +
39+
'* @file js-data-angular.min.js\n' +
40+
'* @version <%= pkg.version %> - Homepage <https://www.js-data.io/js-data-angular/>\n' +
41+
'* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>\n' +
42+
'* @license MIT <https://github.com/js-data/js-data-angular/blob/master/LICENSE>\n' +
43+
'*\n' +
44+
'* @overview Angular wrapper for js-data.\n' +
45+
'*/\n'
4646
},
4747
files: {
4848
'dist/js-data-angular.min.js': ['dist/js-data-angular.js']
@@ -63,6 +63,39 @@ module.exports = function (grunt) {
6363
'dist/js-data-angular.js': ['src/index.js']
6464
}
6565
}
66+
},
67+
karma: {
68+
options: {
69+
configFile: './karma.conf.js'
70+
},
71+
dev: {
72+
browsers: ['Chrome'],
73+
autoWatch: true,
74+
singleRun: false,
75+
reporters: ['spec'],
76+
preprocessors: {}
77+
},
78+
min: {
79+
browsers: ['Firefox', 'PhantomJS'],
80+
options: {
81+
files: [
82+
'bower_components/angular-1.3.2/angular.js',
83+
'bower_components/angular-mocks-1.3.2/angular-mocks.js',
84+
'bower_components/js-data/dist/js-data.js',
85+
'dist/js-data-angular.min.js',
86+
'karma.start.js',
87+
'test/**/*.js'
88+
]
89+
}
90+
},
91+
ci: {
92+
browsers: ['Firefox', 'PhantomJS']
93+
}
94+
},
95+
coveralls: {
96+
options: {
97+
coverage_dir: 'coverage'
98+
}
6699
}
67100
});
68101

@@ -101,4 +134,5 @@ module.exports = function (grunt) {
101134
]);
102135
grunt.registerTask('go', ['build', 'watch:dist']);
103136
grunt.registerTask('default', ['build']);
137+
grunt.registerTask('test', ['build', 'karma:min']);
104138
};

‎bower.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"author": "Jason Dobry",
33
"name": "js-data-angular",
44
"description": "Angular wrapper for js-data (originally angular-data).",
5-
"version": "2.0.0-alpha.1-0",
5+
"version": "2.0.0-alpha.2-0",
66
"homepage": "http://www.js-data.io/js-data-angular",
77
"repository": {
88
"type": "git",
9-
"url": "git://github.com/js-data/js-data-angular.git"
9+
"url": "https://github.com/js-data/js-data-angular.git"
1010
},
1111
"main": "./dist/js-data-angular.min.js",
1212
"ignore": [
@@ -18,7 +18,20 @@
1818
"node_modules/",
1919
"package.json"
2020
],
21+
"devDependencies": {
22+
"angular-1.1.5": "angular-unstable#1.1.5",
23+
"angular-1.2.16": "angular#1.2.16",
24+
"angular-1.2.25": "angular#1.2.25",
25+
"angular-1.3.2": "angular#1.3.2",
26+
"angular-mocks-1.1.5": "angular-mocks-unstable#1.1.5",
27+
"angular-mocks-1.2.16": "angular-mocks#1.2.16",
28+
"angular-mocks-1.2.25": "angular-mocks#1.2.25",
29+
"angular-mocks-1.3.2": "angular-mocks#1.3.2"
30+
},
2131
"dependencies": {
2232
"js-data": "~1.0.x"
33+
},
34+
"resolutions": {
35+
"angular": "1.3.2"
2336
}
2437
}

‎dist/js-data-angular.js

Lines changed: 199 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @author Jason Dobry <jason.dobry@gmail.com>
33
* @file js-data-angular.js
4-
* @version 2.0.0-alpha.1-0 - Homepage <http://www.js-data.io/js-data-angular/>
4+
* @version 2.0.0-alpha.2-0 - Homepage <http://www.js-data.io/js-data-angular/>
55
* @copyright (c) 2014 Jason Dobry <https://github.com/jmdobry/>
66
* @license MIT <https://github.com/js-data/js-data-angular/blob/master/LICENSE>
77
*
@@ -107,6 +107,176 @@
107107
registerAdapter(adapters[i]);
108108
}
109109

110+
angular.module('js-data', ['ng'])
111+
.value('DSUtils', JSData.DSUtils)
112+
.value('DSErrors', JSData.DSErrors)
113+
.provider('DS', function () {
114+
115+
var _this = this;
116+
var DSUtils = JSData.DSUtils;
117+
var DSErrors = JSData.DSErrors;
118+
var deps = [];
119+
120+
for (var i = 0; i < adapters.length; i++) {
121+
if (adapters[i].loaded) {
122+
deps.push(adapters[i].class);
123+
}
124+
}
125+
126+
_this.defaults = {};
127+
128+
JSData.DS.prototype.bindAll = function (resourceName, params, scope, expr, cb) {
129+
var _this = this;
130+
131+
params = params || {};
132+
133+
if (!_this.definitions[resourceName]) {
134+
throw new DSErrors.NER(resourceName);
135+
} else if (!DSUtils.isObject(params)) {
136+
throw new DSErrors.IA('"params" must be an object!');
137+
} else if (!DSUtils.isObject(scope)) {
138+
throw new DSErrors.IA('"scope" must be an object!');
139+
} else if (!DSUtils.isString(expr)) {
140+
throw new DSErrors.IA('"expr" must be a string!');
141+
}
142+
143+
try {
144+
return scope.$watch(function () {
145+
return _this.lastModified(resourceName);
146+
}, function () {
147+
var items = _this.filter(resourceName, params);
148+
DSUtils.set(scope, expr, items);
149+
if (cb) {
150+
cb(null, items);
151+
}
152+
});
153+
} catch (err) {
154+
if (cb) {
155+
cb(err);
156+
} else {
157+
throw err;
158+
}
159+
}
160+
};
161+
162+
JSData.DS.prototype.bindOne = function (resourceName, id, scope, expr, cb) {
163+
var _this = this;
164+
165+
id = DSUtils.resolveId(_this.definitions[resourceName], id);
166+
if (!DS.definitions[resourceName]) {
167+
throw new DSErrors.NER(resourceName);
168+
} else if (!DSUtils.isString(id) && !DSUtils.isNumber(id)) {
169+
throw new DSErrors.IA('"id" must be a string or a number!');
170+
} else if (!DSUtils.isObject(scope)) {
171+
throw new DSErrors.IA('"scope" must be an object!');
172+
} else if (!DSUtils.isString(expr)) {
173+
throw new DSErrors.IA('"expr" must be a string!');
174+
}
175+
176+
try {
177+
return scope.$watch(function () {
178+
return _this.lastModified(resourceName, id);
179+
}, function () {
180+
var item = _this.get(resourceName, id);
181+
DSUtils.set(scope, expr, item);
182+
if (cb) {
183+
cb(null, item);
184+
}
185+
});
186+
} catch (err) {
187+
if (cb) {
188+
cb(err);
189+
} else {
190+
throw err;
191+
}
192+
}
193+
};
194+
195+
function load() {
196+
var args = Array.prototype.slice.call(arguments);
197+
var $rootScope = args[args.length - 2];
198+
var $q = args[args.length - 1];
199+
var store = new JSData.DS(_this.defaults);
200+
var originals = {};
201+
202+
function QPromise(cb) {
203+
var deferred = $q.defer();
204+
try {
205+
cb(function (val) {
206+
if (!$rootScope.$$phase) {
207+
$rootScope.$apply(function () {
208+
deferred.resolve(val);
209+
});
210+
} else {
211+
deferred.resolve(val);
212+
}
213+
}, function (err) {
214+
console.log(err);
215+
if (!$rootScope.$$phase) {
216+
$rootScope.$apply(function () {
217+
deferred.reject(err);
218+
});
219+
} else {
220+
deferred.reject(err);
221+
}
222+
});
223+
} catch (err) {
224+
deferred.reject(err);
225+
}
226+
return deferred.promise;
227+
}
228+
229+
//QPromise.all = $q.all;
230+
//QPromise.when = $q.when;
231+
//QPromise.reject = $q.reject;
232+
//
233+
//DSUtils.Promise = QPromise;
234+
235+
// Register any adapters that have been loaded
236+
for (var i = 0; i < adapters.length; i++) {
237+
if (adapters[i].loaded) {
238+
store.registerAdapter(adapters[i].name, arguments[i]);
239+
}
240+
}
241+
242+
// Wrap certain sync functions with $apply
243+
for (i = 0; i < functionsToWrap.length; i++) {
244+
originals[functionsToWrap[i]] = store[functionsToWrap[i]];
245+
store[functionsToWrap[i]] = (function (name) {
246+
return function () {
247+
var args = arguments;
248+
if (!$rootScope.$$phase) {
249+
return $rootScope.$apply(function () {
250+
return originals[name].apply(store, args);
251+
});
252+
}
253+
return originals[name].apply(store, args);
254+
};
255+
})(functionsToWrap[i]);
256+
}
257+
258+
// Hook into the digest loop (throttled)
259+
if (typeof Object.observe !== 'function' ||
260+
typeof Array.observe !== 'function') {
261+
$rootScope.$watch(function () {
262+
// TODO: observe.Platform.performMicrotaskCheckpoint();
263+
// Throttle angular-data's digest loop to tenths of a second
264+
return new Date().getTime() / 100 | 0;
265+
}, function () {
266+
store.digest();
267+
});
268+
}
269+
270+
return store;
271+
}
272+
273+
deps.push('$rootScope');
274+
deps.push('$q');
275+
deps.push(load);
276+
277+
_this.$get = deps;
278+
});
279+
110280
if (!httpLoaded) {
111281
var defaultsPrototype = Defaults.prototype;
112282

@@ -120,8 +290,13 @@
120290

121291
defaultsPrototype.httpConfig = {};
122292

123-
defaultsPrototype.log = console ? function (a, b, c, d, e) {
124-
console.log(a, b, c, d, e);
293+
defaultsPrototype.log = console ? function (a, b) {
294+
console[typeof console.info === 'function' ? 'info' : 'log'](a, b);
295+
} : function () {
296+
};
297+
298+
defaultsPrototype.error = console ? function (a, b) {
299+
console[typeof console.error === 'function' ? 'error' : 'log'](a, b);
125300
} : function () {
126301
};
127302

@@ -283,161 +458,40 @@
283458
angular.module('js-data').provider('DSHttpAdapter', function () {
284459
var _this = this;
285460
_this.defaults = {};
286-
_this.$get = ['$http', function ($http) {
461+
_this.$get = ['$http', 'DS', '$q', function ($http, DS, $q) {
287462
dsHttpAdapterPrototype.HTTP = function (config) {
288463
var _this = this;
289-
var start = new Date().getTime();
464+
var start = new Date();
290465
config = deepMixIn(config, _this.defaults.httpConfig);
291466
if (_this.defaults.forceTrailingSlash && config.url[config.url.length] !== '/') {
292467
config.url += '/';
293468
}
294469
config.method = config.method.toUpperCase();
295-
return $http(config).then(function (data) {
296-
if (_this.defaults.log) {
297-
_this.defaults.log(data.config.method.toUpperCase() + ' request: ' + data.config.url + ' Time taken: ' + (new Date().getTime() - start) + 'ms', data);
298-
}
299-
return data;
300-
});
301-
};
302-
303-
return new DSHttpAdapter(_this.defaults);
304-
}];
305-
});
306-
}
307-
308-
angular.module('js-data', ['ng'])
309-
.value('DSUtils', JSData.DSUtils)
310-
.value('DSErrors', JSData.DSErrors)
311-
.provider('DS', function () {
312-
313-
var _this = this;
314-
var DSUtils = JSData.DSUtils;
315-
var DSErrors = JSData.DSErrors;
316-
var deps = [];
317-
318-
for (var i = 0; i < adapters.length; i++) {
319-
if (adapters[i].loaded) {
320-
deps.push(adapters[i].class);
321-
}
322-
}
323-
324-
_this.defaults = {};
325-
326-
JSData.DS.prototype.bindAll = function (scope, expr, resourceName, params, cb) {
327-
var _this = this;
328-
329-
params = params || {};
330-
331-
if (!DSUtils.isObject(scope)) {
332-
throw new DSErrors.IA('"scope" must be an object!');
333-
} else if (!DSUtils.isString(expr)) {
334-
throw new DSErrors.IA('"expr" must be a string!');
335-
} else if (!_this.definitions[resourceName]) {
336-
throw new DSErrors.NER(resourceName);
337-
} else if (!DSUtils.isObject(params)) {
338-
throw new DSErrors.IA('"params" must be an object!');
339-
}
340-
341-
try {
342-
return scope.$watch(function () {
343-
return _this.lastModified(resourceName);
344-
}, function () {
345-
var items = _this.filter(resourceName, params);
346-
DSUtils.set(scope, expr, items);
347-
if (cb) {
348-
cb(null, items);
349-
}
350-
});
351-
} catch (err) {
352-
if (cb) {
353-
cb(err);
354-
} else {
355-
throw err;
356-
}
357-
}
358-
};
359-
360-
JSData.DS.prototype.bindAll = function (scope, expr, resourceName, id, cb) {
361-
var _this = this;
362-
363-
id = DSUtils.resolveId(_this.definitions[resourceName], id);
364-
if (!DSUtils.isObject(scope)) {
365-
throw new DSErrors.IA('"scope" must be an object!');
366-
} else if (!DSUtils.isString(expr)) {
367-
throw new DSErrors.IA('"expr" must be a string!');
368-
} else if (!DS.definitions[resourceName]) {
369-
throw new DSErrors.NER(resourceName);
370-
} else if (!DSUtils.isString(id) && !DSUtils.isNumber(id)) {
371-
throw new DSErrors.IA('"id" must be a string or a number!');
372-
}
373470

374-
try {
375-
return scope.$watch(function () {
376-
return _this.lastModified(resourceName, id);
377-
}, function () {
378-
var item = _this.get(resourceName, id);
379-
DSUtils.set(scope, expr, item);
380-
if (cb) {
381-
cb(null, item);
471+
function logResponse(data) {
472+
var str = start.toUTCString() + ' - ' + data.config.method.toUpperCase() + ' ' + data.config.url + ' - ' + data.status + ' ' + (new Date().getTime() - start.getTime()) + 'ms';
473+
if (data.status >= 200 && data.status < 300) {
474+
if (_this.defaults.log) {
475+
_this.defaults.log(str, data);
476+
}
477+
return data;
478+
} else {
479+
if (_this.defaults.error) {
480+
_this.defaults.error('FAILED: ' + str, data);
481+
}
482+
return $q.reject(data);
382483
}
383-
});
384-
} catch (err) {
385-
if (cb) {
386-
cb(err);
387-
} else {
388-
throw err;
389484
}
390-
}
391-
};
392-
393-
function load() {
394-
var args = Array.prototype.slice.call(arguments);
395-
var $rootScope = args[args.length - 1];
396-
var store = new JSData.DS(_this.defaults);
397-
var originals = {};
398-
399-
// Register any adapters that have been loaded
400-
for (var i = 0; i < adapters.length; i++) {
401-
if (adapters[i].loaded) {
402-
store.registerAdapter(adapters[i].name, arguments[i]);
403-
}
404-
}
405-
406-
// Wrap certain sync functions with $apply
407-
for (i = 0; i < functionsToWrap.length; i++) {
408-
originals[functionsToWrap[i]] = store[functionsToWrap[i]];
409-
store[functionsToWrap[i]] = (function (name) {
410-
return function () {
411-
var args = arguments;
412-
if (!$rootScope.$$phase) {
413-
return $rootScope.$apply(function () {
414-
return originals[name].apply(store, args);
415-
});
416-
}
417-
return originals[name].apply(store, args);
418-
};
419-
})(functionsToWrap[i]);
420-
}
421-
422-
// Hook into the digest loop (throttled)
423-
if (typeof Object.observe !== 'function' ||
424-
typeof Array.observe !== 'function') {
425-
$rootScope.$watch(function () {
426-
// Throttle angular-data's digest loop to tenths of a second
427-
return new Date().getTime() / 100 | 0;
428-
}, function () {
429-
store.digest();
430-
});
431-
}
432485

433-
return store;
434-
}
435-
436-
deps.push('$rootScope');
437-
deps.push(load);
486+
return $http(config).then(logResponse, logResponse);
487+
};
438488

439-
_this.$get = deps;
489+
var adapter = new DSHttpAdapter(_this.defaults);
490+
DS.registerAdapter('http', adapter, { default: true });
491+
return adapter;
492+
}];
440493
});
494+
}
441495

442496
})(window, window.angular);
443497

‎dist/js-data-angular.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎karma.conf.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// an example karma.conf.js
2+
module.exports = function (config) {
3+
config.set({
4+
// base path, that will be used to resolve files and exclude
5+
basePath: './',
6+
frameworks: ['sinon', 'chai', 'mocha'],
7+
plugins: [
8+
// these plugins will be require() by Karma
9+
'karma-sinon',
10+
'karma-mocha',
11+
'karma-chai',
12+
'karma-chrome-launcher',
13+
'karma-phantomjs-launcher',
14+
'karma-firefox-launcher',
15+
'karma-coverage',
16+
'karma-spec-reporter'
17+
],
18+
autoWatch: false,
19+
browserNoActivityTimeout: 30000,
20+
browsers: ['Chrome'],
21+
22+
// list of files / patterns to load in the browser
23+
files: [
24+
'bower_components/angular-1.3.2/angular.js',
25+
'bower_components/angular-mocks-1.3.2/angular-mocks.js',
26+
'bower_components/js-data/dist/js-data.js',
27+
'dist/js-data-angular.js',
28+
'karma.start.js',
29+
'test/**/*.js'
30+
],
31+
32+
reporters: ['spec', 'coverage'],
33+
34+
preprocessors: {
35+
'dist/js-data-angular.js': ['coverage']
36+
},
37+
38+
// optionally, configure the reporter
39+
coverageReporter: {
40+
type: 'lcov',
41+
dir: 'coverage/'
42+
},
43+
44+
// web server port
45+
port: 9876,
46+
47+
// cli runner port
48+
runnerPort: 9100,
49+
50+
// enable / disable colors in the output (reporters and logs)
51+
colors: true,
52+
53+
// level of logging
54+
logLevel: config.LOG_INFO,
55+
56+
// If browser does not capture in given timeout [ms], kill it
57+
captureTimeout: 30000,
58+
59+
// Continuous Integration mode
60+
// if true, it capture browsers, run tests and exit
61+
singleRun: true
62+
});
63+
};

‎karma.start.js

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
// Setup global test variables
2+
var $rootScope, $q, $log, $timeout, DSHttpAdapterProvider, DSProvider, DS, DSUtils, DSHttpAdapter, app, $httpBackend, p1, p2, p3, p4, p5;
3+
4+
var Post, User, Organization, Comment, Profile;
5+
var user1, organization2, comment3, profile4;
6+
var comment11, comment12, comment13, organization14, profile15, user10, user16, user17, user18, organization15, user19, user20, comment19, user22, profile21;
7+
8+
var lifecycle = {};
9+
10+
// Helper globals
11+
var fail = function (msg) {
12+
if (msg instanceof Error) {
13+
console.log(msg.stack);
14+
} else {
15+
assert.equal('should not reach this!: ' + msg, 'failure');
16+
}
17+
},
18+
TYPES_EXCEPT_STRING = [123, 123.123, null, undefined, {}, [], true, false, function () {
19+
}],
20+
TYPES_EXCEPT_STRING_OR_ARRAY = [123, 123.123, null, undefined, {}, true, false, function () {
21+
}],
22+
TYPES_EXCEPT_STRING_OR_OBJECT = [123, 123.123, null, undefined, [], true, false, function () {
23+
}],
24+
TYPES_EXCEPT_STRING_OR_NUMBER_OBJECT = [null, undefined, [], true, false, function () {
25+
}],
26+
TYPES_EXCEPT_ARRAY = ['string', 123, 123.123, null, undefined, {}, true, false, function () {
27+
}],
28+
TYPES_EXCEPT_STRING_OR_NUMBER = [null, undefined, {}, [], true, false, function () {
29+
}],
30+
TYPES_EXCEPT_STRING_OR_ARRAY_OR_NUMBER = [null, undefined, {}, true, false, function () {
31+
}],
32+
TYPES_EXCEPT_NUMBER = ['string', null, undefined, {}, [], true, false, function () {
33+
}],
34+
TYPES_EXCEPT_OBJECT = ['string', 123, 123.123, null, undefined, true, false, function () {
35+
}],
36+
TYPES_EXCEPT_BOOLEAN = ['string', 123, 123.123, null, undefined, {}, [], function () {
37+
}],
38+
TYPES_EXCEPT_FUNCTION = ['string', 123, 123.123, null, undefined, {}, [], true, false];
39+
40+
angular.module('app', ['ng', 'js-data']);
41+
42+
// Setup before each test
43+
beforeEach(function () {
44+
lifecycle.beforeValidate = function (resourceName, attrs, cb) {
45+
lifecycle.beforeValidate.callCount += 1;
46+
cb(null, attrs);
47+
};
48+
lifecycle.validate = function (resourceName, attrs, cb) {
49+
lifecycle.validate.callCount += 1;
50+
cb(null, attrs);
51+
};
52+
lifecycle.afterValidate = function (resourceName, attrs, cb) {
53+
lifecycle.afterValidate.callCount += 1;
54+
cb(null, attrs);
55+
};
56+
lifecycle.beforeCreate = function (resourceName, attrs, cb) {
57+
lifecycle.beforeCreate.callCount += 1;
58+
cb(null, attrs);
59+
};
60+
lifecycle.afterCreate = function (resourceName, attrs, cb) {
61+
lifecycle.afterCreate.callCount += 1;
62+
cb(null, attrs);
63+
};
64+
lifecycle.beforeUpdate = function (resourceName, attrs, cb) {
65+
lifecycle.beforeUpdate.callCount += 1;
66+
cb(null, attrs);
67+
};
68+
lifecycle.afterUpdate = function (resourceName, attrs, cb) {
69+
lifecycle.afterUpdate.callCount += 1;
70+
cb(null, attrs);
71+
};
72+
lifecycle.beforeDestroy = function (resourceName, attrs, cb) {
73+
lifecycle.beforeDestroy.callCount += 1;
74+
cb(null, attrs);
75+
};
76+
lifecycle.afterDestroy = function (resourceName, attrs, cb) {
77+
lifecycle.afterDestroy.callCount += 1;
78+
cb(null, attrs);
79+
};
80+
lifecycle.beforeInject = function () {
81+
lifecycle.beforeInject.callCount += 1;
82+
};
83+
lifecycle.afterInject = function () {
84+
lifecycle.afterInject.callCount += 1;
85+
};
86+
lifecycle.serialize = function (resourceName, data) {
87+
lifecycle.serialize.callCount += 1;
88+
return data;
89+
};
90+
lifecycle.deserialize = function (resourceName, data) {
91+
lifecycle.deserialize.callCount += 1;
92+
return data ? (data.data ? data.data : data) : data;;
93+
};
94+
lifecycle.queryTransform = function (resourceName, query) {
95+
lifecycle.queryTransform.callCount += 1;
96+
return query;
97+
};
98+
module('app', function (_DSProvider_, _DSHttpAdapterProvider_) {
99+
DSProvider = _DSProvider_;
100+
DSProvider.defaults.basePath = 'http://test.angular-cache.com';
101+
DSProvider.defaults.beforeValidate = lifecycle.beforeValidate;
102+
DSProvider.defaults.validate = lifecycle.validate;
103+
DSProvider.defaults.afterValidate = lifecycle.afterValidate;
104+
DSProvider.defaults.beforeCreate = lifecycle.beforeCreate;
105+
DSProvider.defaults.afterCreate = lifecycle.afterCreate;
106+
DSProvider.defaults.beforeUpdate = lifecycle.beforeUpdate;
107+
DSProvider.defaults.afterUpdate = lifecycle.afterUpdate;
108+
DSProvider.defaults.beforeDestroy = lifecycle.beforeDestroy;
109+
DSProvider.defaults.afterDestroy = lifecycle.afterDestroy;
110+
DSProvider.defaults.beforeInject = lifecycle.beforeInject;
111+
DSProvider.defaults.afterInject = lifecycle.afterInject;
112+
DSProvider.defaults.serialize = lifecycle.serialize;
113+
DSProvider.defaults.deserialize = lifecycle.deserialize;
114+
DSHttpAdapterProvider = _DSHttpAdapterProvider_;
115+
DSHttpAdapterProvider.defaults.queryTransform = lifecycle.queryTransform;
116+
DSHttpAdapterProvider.defaults.log = false;
117+
});
118+
});
119+
120+
function startInjector() {
121+
inject(function (_$rootScope_, _$q_, _$timeout_, _$httpBackend_, _DS_, _$log_, _DSUtils_, _DSHttpAdapter_) {
122+
// Setup global mocks
123+
124+
localStorage.clear();
125+
$q = _$q_;
126+
$rootScope = _$rootScope_;
127+
DS = _DS_;
128+
$timeout = _$timeout_;
129+
DSUtils = _DSUtils_;
130+
DSHttpAdapter = _DSHttpAdapter_;
131+
$httpBackend = _$httpBackend_;
132+
Post = DS.defineResource({
133+
name: 'post',
134+
keepChangeHistory: true,
135+
endpoint: '/posts'
136+
});
137+
User = DS.defineResource({
138+
name: 'user',
139+
relations: {
140+
hasMany: {
141+
comment: {
142+
localField: 'comments',
143+
foreignKey: 'approvedBy'
144+
}
145+
},
146+
hasOne: {
147+
profile: {
148+
localField: 'profile',
149+
foreignKey: 'userId'
150+
}
151+
},
152+
belongsTo: {
153+
organization: {
154+
parent: true,
155+
localKey: 'organizationId',
156+
localField: 'organization'
157+
}
158+
}
159+
}
160+
});
161+
162+
Organization = DS.defineResource({
163+
name: 'organization',
164+
relations: {
165+
hasMany: {
166+
user: {
167+
localField: 'users',
168+
foreignKey: 'organizationId'
169+
}
170+
}
171+
}
172+
});
173+
174+
Profile = DS.defineResource({
175+
name: 'profile',
176+
relations: {
177+
belongsTo: {
178+
user: {
179+
localField: 'user',
180+
localKey: 'userId'
181+
}
182+
}
183+
}
184+
});
185+
186+
Comment = DS.defineResource({
187+
name: 'comment',
188+
relations: {
189+
belongsTo: {
190+
user: [
191+
{
192+
localField: 'user',
193+
localKey: 'userId'
194+
},
195+
{
196+
parent: true,
197+
localField: 'approvedByUser',
198+
localKey: 'approvedBy'
199+
}
200+
]
201+
}
202+
}
203+
});
204+
$log = _$log_;
205+
206+
lifecycle.beforeValidate.callCount = 0;
207+
lifecycle.validate.callCount = 0;
208+
lifecycle.afterValidate.callCount = 0;
209+
lifecycle.beforeCreate.callCount = 0;
210+
lifecycle.afterCreate.callCount = 0;
211+
lifecycle.beforeUpdate.callCount = 0;
212+
lifecycle.afterUpdate.callCount = 0;
213+
lifecycle.beforeDestroy.callCount = 0;
214+
lifecycle.afterDestroy.callCount = 0;
215+
lifecycle.beforeInject.callCount = 0;
216+
lifecycle.afterInject.callCount = 0;
217+
lifecycle.serialize.callCount = 0;
218+
lifecycle.deserialize.callCount = 0;
219+
lifecycle.queryTransform.callCount = 0;
220+
221+
p1 = { author: 'John', age: 30, id: 5 };
222+
p2 = { author: 'Sally', age: 31, id: 6 };
223+
p3 = { author: 'Mike', age: 32, id: 7 };
224+
p4 = { author: 'Adam', age: 33, id: 8 };
225+
p5 = { author: 'Adam', age: 33, id: 9 };
226+
227+
user1 = {
228+
name: 'John Anderson',
229+
id: 1,
230+
organizationId: 2
231+
};
232+
organization2 = {
233+
name: 'Test Corp 2',
234+
id: 2
235+
};
236+
comment3 = {
237+
content: 'test comment 3',
238+
id: 3,
239+
userId: 1
240+
};
241+
profile4 = {
242+
content: 'test profile 4',
243+
id: 4,
244+
userId: 1
245+
};
246+
247+
comment11 = {
248+
id: 11,
249+
userId: 10,
250+
content: 'test comment 11'
251+
};
252+
comment12 = {
253+
id: 12,
254+
userId: 10,
255+
content: 'test comment 12'
256+
};
257+
comment13 = {
258+
id: 13,
259+
userId: 10,
260+
content: 'test comment 13'
261+
};
262+
organization14 = {
263+
id: 14,
264+
name: 'Test Corp'
265+
};
266+
profile15 = {
267+
id: 15,
268+
userId: 10,
269+
email: 'john.anderson@test.com'
270+
};
271+
user10 = {
272+
name: 'John Anderson',
273+
id: 10,
274+
organizationId: 14,
275+
comments: [
276+
comment11,
277+
comment12,
278+
comment13
279+
],
280+
organization: organization14,
281+
profile: profile15
282+
};
283+
user16 = {
284+
id: 16,
285+
organizationId: 15,
286+
name: 'test user 16'
287+
};
288+
user17 = {
289+
id: 17,
290+
organizationId: 15,
291+
name: 'test user 17'
292+
};
293+
user18 = {
294+
id: 18,
295+
organizationId: 15,
296+
name: 'test user 18'
297+
};
298+
organization15 = {
299+
name: 'Another Test Corp',
300+
id: 15,
301+
users: [
302+
user16,
303+
user17,
304+
user18
305+
]
306+
};
307+
user19 = {
308+
id: 19,
309+
name: 'test user 19'
310+
};
311+
user20 = {
312+
id: 20,
313+
name: 'test user 20'
314+
};
315+
comment19 = {
316+
content: 'test comment 19',
317+
id: 19,
318+
approvedBy: 19,
319+
approvedByUser: user19,
320+
userId: 20,
321+
user: user20
322+
};
323+
user22 = {
324+
id: 22,
325+
name: 'test user 22'
326+
};
327+
profile21 = {
328+
content: 'test profile 21',
329+
id: 21,
330+
userId: 22,
331+
user: user22
332+
};
333+
});
334+
}
335+
336+
// Clean up after each test
337+
afterEach(function () {
338+
$httpBackend.verifyNoOutstandingExpectation();
339+
$httpBackend.verifyNoOutstandingRequest();
340+
$log.reset();
341+
});

‎package.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "js-data-angular",
33
"description": "Angular wrapper for js-data.",
4-
"version": "2.0.0-alpha.1-0",
4+
"version": "2.0.0-alpha.2-0",
55
"homepage": "http://js-data-angular.pseudobry.com",
66
"repository": {
77
"type": "git",
@@ -20,11 +20,23 @@
2020
],
2121
"devDependencies": {
2222
"grunt": "0.4.5",
23-
"grunt-browserify": "3.1.0",
23+
"grunt-browserify": "3.2.0",
2424
"grunt-contrib-clean": "0.6.0",
2525
"grunt-contrib-jshint": "0.10.0",
2626
"grunt-contrib-uglify": "0.6.0",
2727
"grunt-contrib-watch": "0.6.1",
28+
"grunt-karma": "0.9.0",
29+
"grunt-karma-coveralls": "2.5.2",
30+
"karma": "0.12.24",
31+
"karma-chai": "0.1.0",
32+
"karma-chrome-launcher": "0.1.5",
33+
"karma-coverage": "0.2.6",
34+
"karma-script-launcher": "0.1.0",
35+
"karma-firefox-launcher": "0.1.3",
36+
"karma-phantomjs-launcher": "0.1.4",
37+
"karma-mocha": "0.1.9",
38+
"karma-sinon": "1.0.3",
39+
"karma-spec-reporter": "0.0.13",
2840
"time-grunt": "1.0.0",
2941
"jit-grunt": "0.9.0"
3042
},

‎src/index.js

Lines changed: 198 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,176 @@
9797
registerAdapter(adapters[i]);
9898
}
9999

100+
angular.module('js-data', ['ng'])
101+
.value('DSUtils', JSData.DSUtils)
102+
.value('DSErrors', JSData.DSErrors)
103+
.provider('DS', function () {
104+
105+
var _this = this;
106+
var DSUtils = JSData.DSUtils;
107+
var DSErrors = JSData.DSErrors;
108+
var deps = [];
109+
110+
for (var i = 0; i < adapters.length; i++) {
111+
if (adapters[i].loaded) {
112+
deps.push(adapters[i].class);
113+
}
114+
}
115+
116+
_this.defaults = {};
117+
118+
JSData.DS.prototype.bindAll = function (resourceName, params, scope, expr, cb) {
119+
var _this = this;
120+
121+
params = params || {};
122+
123+
if (!_this.definitions[resourceName]) {
124+
throw new DSErrors.NER(resourceName);
125+
} else if (!DSUtils.isObject(params)) {
126+
throw new DSErrors.IA('"params" must be an object!');
127+
} else if (!DSUtils.isObject(scope)) {
128+
throw new DSErrors.IA('"scope" must be an object!');
129+
} else if (!DSUtils.isString(expr)) {
130+
throw new DSErrors.IA('"expr" must be a string!');
131+
}
132+
133+
try {
134+
return scope.$watch(function () {
135+
return _this.lastModified(resourceName);
136+
}, function () {
137+
var items = _this.filter(resourceName, params);
138+
DSUtils.set(scope, expr, items);
139+
if (cb) {
140+
cb(null, items);
141+
}
142+
});
143+
} catch (err) {
144+
if (cb) {
145+
cb(err);
146+
} else {
147+
throw err;
148+
}
149+
}
150+
};
151+
152+
JSData.DS.prototype.bindOne = function (resourceName, id, scope, expr, cb) {
153+
var _this = this;
154+
155+
id = DSUtils.resolveId(_this.definitions[resourceName], id);
156+
if (!DS.definitions[resourceName]) {
157+
throw new DSErrors.NER(resourceName);
158+
} else if (!DSUtils.isString(id) && !DSUtils.isNumber(id)) {
159+
throw new DSErrors.IA('"id" must be a string or a number!');
160+
} else if (!DSUtils.isObject(scope)) {
161+
throw new DSErrors.IA('"scope" must be an object!');
162+
} else if (!DSUtils.isString(expr)) {
163+
throw new DSErrors.IA('"expr" must be a string!');
164+
}
165+
166+
try {
167+
return scope.$watch(function () {
168+
return _this.lastModified(resourceName, id);
169+
}, function () {
170+
var item = _this.get(resourceName, id);
171+
DSUtils.set(scope, expr, item);
172+
if (cb) {
173+
cb(null, item);
174+
}
175+
});
176+
} catch (err) {
177+
if (cb) {
178+
cb(err);
179+
} else {
180+
throw err;
181+
}
182+
}
183+
};
184+
185+
function load() {
186+
var args = Array.prototype.slice.call(arguments);
187+
var $rootScope = args[args.length - 2];
188+
var $q = args[args.length - 1];
189+
var store = new JSData.DS(_this.defaults);
190+
var originals = {};
191+
192+
function QPromise(cb) {
193+
var deferred = $q.defer();
194+
try {
195+
cb(function (val) {
196+
if (!$rootScope.$$phase) {
197+
$rootScope.$apply(function () {
198+
deferred.resolve(val);
199+
});
200+
} else {
201+
deferred.resolve(val);
202+
}
203+
}, function (err) {
204+
console.log(err);
205+
if (!$rootScope.$$phase) {
206+
$rootScope.$apply(function () {
207+
deferred.reject(err);
208+
});
209+
} else {
210+
deferred.reject(err);
211+
}
212+
});
213+
} catch (err) {
214+
deferred.reject(err);
215+
}
216+
return deferred.promise;
217+
}
218+
219+
//QPromise.all = $q.all;
220+
//QPromise.when = $q.when;
221+
//QPromise.reject = $q.reject;
222+
//
223+
//DSUtils.Promise = QPromise;
224+
225+
// Register any adapters that have been loaded
226+
for (var i = 0; i < adapters.length; i++) {
227+
if (adapters[i].loaded) {
228+
store.registerAdapter(adapters[i].name, arguments[i]);
229+
}
230+
}
231+
232+
// Wrap certain sync functions with $apply
233+
for (i = 0; i < functionsToWrap.length; i++) {
234+
originals[functionsToWrap[i]] = store[functionsToWrap[i]];
235+
store[functionsToWrap[i]] = (function (name) {
236+
return function () {
237+
var args = arguments;
238+
if (!$rootScope.$$phase) {
239+
return $rootScope.$apply(function () {
240+
return originals[name].apply(store, args);
241+
});
242+
}
243+
return originals[name].apply(store, args);
244+
};
245+
})(functionsToWrap[i]);
246+
}
247+
248+
// Hook into the digest loop (throttled)
249+
if (typeof Object.observe !== 'function' ||
250+
typeof Array.observe !== 'function') {
251+
$rootScope.$watch(function () {
252+
// TODO: observe.Platform.performMicrotaskCheckpoint();
253+
// Throttle angular-data's digest loop to tenths of a second
254+
return new Date().getTime() / 100 | 0;
255+
}, function () {
256+
store.digest();
257+
});
258+
}
259+
260+
return store;
261+
}
262+
263+
deps.push('$rootScope');
264+
deps.push('$q');
265+
deps.push(load);
266+
267+
_this.$get = deps;
268+
});
269+
100270
if (!httpLoaded) {
101271
var defaultsPrototype = Defaults.prototype;
102272

@@ -110,8 +280,13 @@
110280

111281
defaultsPrototype.httpConfig = {};
112282

113-
defaultsPrototype.log = console ? function (a, b, c, d, e) {
114-
console.log(a, b, c, d, e);
283+
defaultsPrototype.log = console ? function (a, b) {
284+
console[typeof console.info === 'function' ? 'info' : 'log'](a, b);
285+
} : function () {
286+
};
287+
288+
defaultsPrototype.error = console ? function (a, b) {
289+
console[typeof console.error === 'function' ? 'error' : 'log'](a, b);
115290
} : function () {
116291
};
117292

@@ -273,160 +448,39 @@
273448
angular.module('js-data').provider('DSHttpAdapter', function () {
274449
var _this = this;
275450
_this.defaults = {};
276-
_this.$get = ['$http', function ($http) {
451+
_this.$get = ['$http', 'DS', '$q', function ($http, DS, $q) {
277452
dsHttpAdapterPrototype.HTTP = function (config) {
278453
var _this = this;
279-
var start = new Date().getTime();
454+
var start = new Date();
280455
config = deepMixIn(config, _this.defaults.httpConfig);
281456
if (_this.defaults.forceTrailingSlash && config.url[config.url.length] !== '/') {
282457
config.url += '/';
283458
}
284459
config.method = config.method.toUpperCase();
285-
return $http(config).then(function (data) {
286-
if (_this.defaults.log) {
287-
_this.defaults.log(data.config.method.toUpperCase() + ' request: ' + data.config.url + ' Time taken: ' + (new Date().getTime() - start) + 'ms', data);
288-
}
289-
return data;
290-
});
291-
};
292-
293-
return new DSHttpAdapter(_this.defaults);
294-
}];
295-
});
296-
}
297-
298-
angular.module('js-data', ['ng'])
299-
.value('DSUtils', JSData.DSUtils)
300-
.value('DSErrors', JSData.DSErrors)
301-
.provider('DS', function () {
302-
303-
var _this = this;
304-
var DSUtils = JSData.DSUtils;
305-
var DSErrors = JSData.DSErrors;
306-
var deps = [];
307-
308-
for (var i = 0; i < adapters.length; i++) {
309-
if (adapters[i].loaded) {
310-
deps.push(adapters[i].class);
311-
}
312-
}
313-
314-
_this.defaults = {};
315-
316-
JSData.DS.prototype.bindAll = function (scope, expr, resourceName, params, cb) {
317-
var _this = this;
318-
319-
params = params || {};
320-
321-
if (!DSUtils.isObject(scope)) {
322-
throw new DSErrors.IA('"scope" must be an object!');
323-
} else if (!DSUtils.isString(expr)) {
324-
throw new DSErrors.IA('"expr" must be a string!');
325-
} else if (!_this.definitions[resourceName]) {
326-
throw new DSErrors.NER(resourceName);
327-
} else if (!DSUtils.isObject(params)) {
328-
throw new DSErrors.IA('"params" must be an object!');
329-
}
330-
331-
try {
332-
return scope.$watch(function () {
333-
return _this.lastModified(resourceName);
334-
}, function () {
335-
var items = _this.filter(resourceName, params);
336-
DSUtils.set(scope, expr, items);
337-
if (cb) {
338-
cb(null, items);
339-
}
340-
});
341-
} catch (err) {
342-
if (cb) {
343-
cb(err);
344-
} else {
345-
throw err;
346-
}
347-
}
348-
};
349-
350-
JSData.DS.prototype.bindAll = function (scope, expr, resourceName, id, cb) {
351-
var _this = this;
352-
353-
id = DSUtils.resolveId(_this.definitions[resourceName], id);
354-
if (!DSUtils.isObject(scope)) {
355-
throw new DSErrors.IA('"scope" must be an object!');
356-
} else if (!DSUtils.isString(expr)) {
357-
throw new DSErrors.IA('"expr" must be a string!');
358-
} else if (!DS.definitions[resourceName]) {
359-
throw new DSErrors.NER(resourceName);
360-
} else if (!DSUtils.isString(id) && !DSUtils.isNumber(id)) {
361-
throw new DSErrors.IA('"id" must be a string or a number!');
362-
}
363460

364-
try {
365-
return scope.$watch(function () {
366-
return _this.lastModified(resourceName, id);
367-
}, function () {
368-
var item = _this.get(resourceName, id);
369-
DSUtils.set(scope, expr, item);
370-
if (cb) {
371-
cb(null, item);
461+
function logResponse(data) {
462+
var str = start.toUTCString() + ' - ' + data.config.method.toUpperCase() + ' ' + data.config.url + ' - ' + data.status + ' ' + (new Date().getTime() - start.getTime()) + 'ms';
463+
if (data.status >= 200 && data.status < 300) {
464+
if (_this.defaults.log) {
465+
_this.defaults.log(str, data);
466+
}
467+
return data;
468+
} else {
469+
if (_this.defaults.error) {
470+
_this.defaults.error('FAILED: ' + str, data);
471+
}
472+
return $q.reject(data);
372473
}
373-
});
374-
} catch (err) {
375-
if (cb) {
376-
cb(err);
377-
} else {
378-
throw err;
379474
}
380-
}
381-
};
382-
383-
function load() {
384-
var args = Array.prototype.slice.call(arguments);
385-
var $rootScope = args[args.length - 1];
386-
var store = new JSData.DS(_this.defaults);
387-
var originals = {};
388-
389-
// Register any adapters that have been loaded
390-
for (var i = 0; i < adapters.length; i++) {
391-
if (adapters[i].loaded) {
392-
store.registerAdapter(adapters[i].name, arguments[i]);
393-
}
394-
}
395-
396-
// Wrap certain sync functions with $apply
397-
for (i = 0; i < functionsToWrap.length; i++) {
398-
originals[functionsToWrap[i]] = store[functionsToWrap[i]];
399-
store[functionsToWrap[i]] = (function (name) {
400-
return function () {
401-
var args = arguments;
402-
if (!$rootScope.$$phase) {
403-
return $rootScope.$apply(function () {
404-
return originals[name].apply(store, args);
405-
});
406-
}
407-
return originals[name].apply(store, args);
408-
};
409-
})(functionsToWrap[i]);
410-
}
411-
412-
// Hook into the digest loop (throttled)
413-
if (typeof Object.observe !== 'function' ||
414-
typeof Array.observe !== 'function') {
415-
$rootScope.$watch(function () {
416-
// Throttle angular-data's digest loop to tenths of a second
417-
return new Date().getTime() / 100 | 0;
418-
}, function () {
419-
store.digest();
420-
});
421-
}
422475

423-
return store;
424-
}
425-
426-
deps.push('$rootScope');
427-
deps.push(load);
476+
return $http(config).then(logResponse, logResponse);
477+
};
428478

429-
_this.$get = deps;
479+
var adapter = new DSHttpAdapter(_this.defaults);
480+
DS.registerAdapter('http', adapter, { default: true });
481+
return adapter;
482+
}];
430483
});
484+
}
431485

432486
})(window, window.angular);

‎test/adapters/http/create.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
describe('DSHttpAdapter.create', function () {
2+
3+
beforeEach(startInjector);
4+
5+
it('should make a POST request', function () {
6+
$httpBackend.expectPOST('http://test.angular-cache.com/posts', {
7+
author: 'John',
8+
age: 30
9+
}).respond(200, p1);
10+
11+
DSHttpAdapter.create(Post, { author: 'John', age: 30 }).then(function (data) {
12+
assert.deepEqual(data, p1, 'post should have been created');
13+
}, function (err) {
14+
console.error(err.stack);
15+
fail('should not have rejected');
16+
});
17+
18+
$httpBackend.flush();
19+
20+
$httpBackend.expectPOST('api2/posts', {
21+
author: 'John',
22+
age: 30
23+
}).respond(200, p1);
24+
25+
DSHttpAdapter.create(Post, { author: 'John', age: 30 }, { basePath: 'api2' }).then(function (data) {
26+
assert.deepEqual(data, p1, 'post should have been created');
27+
}, function (err) {
28+
console.error(err.stack);
29+
fail('should not have rejected');
30+
});
31+
32+
$httpBackend.flush();
33+
34+
assert.equal(lifecycle.queryTransform.callCount, 0, 'queryTransform should not have been called');
35+
});
36+
});

‎test/adapters/http/destroy.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
describe('DSHttpAdapter.destroy', function () {
2+
3+
beforeEach(startInjector);
4+
5+
it('should make a DELETE request', function () {
6+
$httpBackend.expectDELETE('http://test.angular-cache.com/posts/1').respond(200, 1);
7+
8+
DSHttpAdapter.destroy(Post, 1).then(function (data) {
9+
assert.deepEqual(data, 1, 'post should have been deleted');
10+
}, function (err) {
11+
console.error(err.stack);
12+
fail('should not have rejected');
13+
});
14+
15+
$httpBackend.flush();
16+
17+
$httpBackend.expectDELETE('api2/posts/1').respond(200, 1);
18+
19+
DSHttpAdapter.destroy(Post, 1, { basePath: 'api2' }).then(function (data) {
20+
assert.deepEqual(data, 1, 'post should have been deleted');
21+
}, function (err) {
22+
console.error(err.stack);
23+
fail('should not have rejected');
24+
});
25+
26+
$httpBackend.flush();
27+
28+
assert.equal(lifecycle.queryTransform.callCount, 0, 'queryTransform should not have been called');
29+
});
30+
});

‎test/adapters/http/destroyAll.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
describe('DSHttpAdapter.destroyAll', function () {
2+
3+
beforeEach(startInjector);
4+
5+
it('should make a DELETE request', function () {
6+
$httpBackend.expectDELETE('http://test.angular-cache.com/posts').respond(204);
7+
8+
DSHttpAdapter.destroyAll(Post, {}).then(function (data) {
9+
assert.isUndefined(data, 'posts should have been found');
10+
}, function (err) {
11+
console.error(err.stack);
12+
fail('should not have rejected');
13+
});
14+
15+
$httpBackend.flush();
16+
17+
$httpBackend.expectDELETE('api2/posts?where=%7B%22author%22:%7B%22%3D%3D%22:%22John%22%7D%7D').respond(204);
18+
19+
DSHttpAdapter.destroyAll(Post, {
20+
where: {
21+
author: {
22+
'==': 'John'
23+
}
24+
}
25+
}, { basePath: 'api2' }).then(function (data) {
26+
assert.isUndefined(data, 'posts should have been destroyed');
27+
}, function (err) {
28+
console.error(err.stack);
29+
fail('should not have rejected');
30+
});
31+
32+
$httpBackend.flush();
33+
34+
assert.equal(lifecycle.queryTransform.callCount, 2, 'queryTransform should have been called');
35+
});
36+
});

‎test/adapters/http/find.test.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
describe('DSHttpAdapter.find', function () {
2+
3+
beforeEach(startInjector);
4+
5+
it('should make a GET request', function () {
6+
$httpBackend.expectGET('http://test.angular-cache.com/posts/1').respond(200, p1);
7+
8+
DSHttpAdapter.find(Post, 1).then(function (data) {
9+
assert.deepEqual(data, p1, 'post should have been found');
10+
}, function (err) {
11+
console.error(err.stack);
12+
fail('should not have rejected');
13+
});
14+
15+
$httpBackend.flush();
16+
17+
$httpBackend.expectGET('api2/posts/1').respond(200, p1);
18+
19+
DSHttpAdapter.find(Post, 1, { basePath: 'api2' }).then(function (data) {
20+
assert.deepEqual(data, p1, 'post should have been found');
21+
}, function (err) {
22+
console.error(err.stack);
23+
fail('should not have rejected');
24+
});
25+
26+
$httpBackend.flush();
27+
28+
assert.equal(lifecycle.queryTransform.callCount, 0, 'queryTransform should not have been called');
29+
});
30+
31+
it('should use default configs', function () {
32+
$httpBackend.expectGET('http://test.angular-cache.com/posts/1?test=test', {
33+
Authorization: 'test',
34+
Accept: 'application/json, text/plain, */*'
35+
}).respond(200, p1);
36+
37+
DSHttpAdapter.defaults.httpConfig.params = { test: 'test' };
38+
DSHttpAdapter.defaults.httpConfig.headers = { Authorization: 'test' };
39+
40+
DSHttpAdapter.find(Post, 1).then(function (data) {
41+
assert.deepEqual(data, p1, 'post should have been found');
42+
}, function (err) {
43+
console.error(err.stack);
44+
fail('should not have rejected');
45+
});
46+
47+
$httpBackend.flush();
48+
49+
delete DSHttpAdapter.defaults.httpConfig.params;
50+
delete DSHttpAdapter.defaults.httpConfig.headers;
51+
});
52+
});

‎test/adapters/http/findAll.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
describe('DSHttpAdapter.findAll', function () {
2+
3+
beforeEach(startInjector);
4+
5+
it('should make a GET request', function () {
6+
$httpBackend.expectGET('http://test.angular-cache.com/posts').respond(200, [p1]);
7+
8+
DSHttpAdapter.findAll(Post, {}).then(function (data) {
9+
assert.deepEqual(data, [p1], 'posts should have been found');
10+
}, function (err) {
11+
console.error(err.stack);
12+
fail('should not have rejected');
13+
});
14+
15+
$httpBackend.flush();
16+
17+
$httpBackend.expectGET('api2/posts?where=%7B%22author%22:%7B%22%3D%3D%22:%22John%22%7D%7D').respond(200, [p1]);
18+
19+
DSHttpAdapter.findAll(Post, {
20+
where: {
21+
author: {
22+
'==': 'John'
23+
}
24+
}
25+
}, { basePath: 'api2' }).then(function (data) {
26+
assert.deepEqual(data, [p1], 'posts should have been found');
27+
}, function (err) {
28+
console.error(err.stack);
29+
fail('should not have rejected');
30+
});
31+
32+
$httpBackend.flush();
33+
34+
assert.equal(lifecycle.queryTransform.callCount, 2, 'queryTransform should have been called');
35+
});
36+
});

‎test/adapters/http/update.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
describe('DSHttpAdapter.update', function () {
2+
3+
beforeEach(startInjector);
4+
5+
it('should make a PUT request', function () {
6+
$httpBackend.expectPUT('http://test.angular-cache.com/posts/1', {
7+
author: 'John',
8+
age: 30
9+
}).respond(200, p1);
10+
11+
DSHttpAdapter.update(Post, 1, { author: 'John', age: 30 }).then(function (data) {
12+
assert.deepEqual(data, p1, 'post 5 should have been updated');
13+
}, function (err) {
14+
console.error(err.stack);
15+
fail('should not have rejected');
16+
});
17+
18+
$httpBackend.flush();
19+
20+
$httpBackend.expectPUT('api2/posts/1', {
21+
author: 'John',
22+
age: 30
23+
}).respond(200, p1);
24+
25+
DSHttpAdapter.update(Post, 1, { author: 'John', age: 30 }, { basePath: 'api2' }).then(function (data) {
26+
assert.deepEqual(data, p1, 'post 5 should have been updated');
27+
}, function (err) {
28+
console.error(err.stack);
29+
fail('should not have rejected');
30+
});
31+
32+
$httpBackend.flush();
33+
34+
assert.equal(lifecycle.queryTransform.callCount, 0, 'queryTransform should not have been called');
35+
});
36+
});

‎test/adapters/http/updateAll.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
describe('DSHttpAdapter.updateAll', function () {
2+
3+
beforeEach(startInjector);
4+
5+
it('should make a PUT request', function () {
6+
$httpBackend.expectPUT('http://test.angular-cache.com/posts').respond(200, [p1]);
7+
8+
DSHttpAdapter.updateAll(Post, { author: 'John', age: 30 }).then(function (data) {
9+
assert.deepEqual(data, [p1], 'posts should have been updated');
10+
}, function (err) {
11+
console.error(err.stack);
12+
fail('should not have rejected');
13+
});
14+
15+
$httpBackend.flush();
16+
17+
$httpBackend.expectPUT('api2/posts?where=%7B%22author%22:%7B%22%3D%3D%22:%22John%22%7D%7D').respond(200, [p1]);
18+
19+
DSHttpAdapter.updateAll(Post, { author: 'John', age: 30 }, {
20+
where: {
21+
author: {
22+
'==': 'John'
23+
}
24+
}
25+
}, { basePath: 'api2' }).then(function (data) {
26+
assert.deepEqual(data, [p1], 'posts should have been updated');
27+
}, function (err) {
28+
console.error(err.stack);
29+
fail('should not have rejected');
30+
});
31+
32+
$httpBackend.flush();
33+
34+
assert.equal(lifecycle.queryTransform.callCount, 1, 'queryTransform should have been called');
35+
});
36+
});
Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
describe('DS.create', function () {
2+
beforeEach(startInjector);
3+
4+
it('should create an item and save it to the server', function (done) {
5+
$httpBackend.expectPOST('http://test.angular-cache.com/posts').respond(200, p1);
6+
7+
DS.create('post', { author: 'John', age: 30 }).then(function (post) {
8+
try {
9+
assert.deepEqual(angular.toJson(post), angular.toJson(p1), 'post 5 should have been created');
10+
11+
assert.equal(lifecycle.beforeCreate.callCount, 1, 'beforeCreate should have been called');
12+
assert.equal(lifecycle.afterCreate.callCount, 1, 'afterCreate should have been called');
13+
assert.equal(lifecycle.beforeInject.callCount, 1, 'beforeInject should have been called');
14+
assert.equal(lifecycle.afterInject.callCount, 1, 'afterInject should have been called');
15+
assert.equal(lifecycle.serialize.callCount, 1, 'serialize should have been called');
16+
assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called');
17+
assert.deepEqual(angular.toJson(DS.get('post', 5)), angular.toJson(p1));
18+
19+
done();
20+
} catch (e) {
21+
done(e);
22+
}
23+
}, function (err) {
24+
console.error(err.stack);
25+
done('should not have rejected');
26+
});
27+
28+
setTimeout(function () {
29+
try {
30+
$httpBackend.flush();
31+
} catch (e) {
32+
done(e);
33+
}
34+
}, 30);
35+
});
36+
it('should create an item and save it to the server but not inject the result', function (done) {
37+
DSHttpAdapter.defaults.forceTrailingSlash = true;
38+
$httpBackend.expectPOST('http://test.angular-cache.com/posts/').respond(200, p1);
39+
40+
DS.create('post', { author: 'John', age: 30 }, { cacheResponse: false }).then(function (post) {
41+
assert.deepEqual(angular.toJson(post), angular.toJson(p1), 'post 5 should have been created');
42+
}, function (err) {
43+
console.error(err.stack);
44+
fail('should not have rejected');
45+
});
46+
47+
setTimeout(function () {
48+
try {
49+
$httpBackend.flush();
50+
51+
setTimeout(function () {
52+
try {
53+
DSHttpAdapter.defaults.forceTrailingSlash = false;
54+
55+
assert.equal(lifecycle.beforeCreate.callCount, 1, 'beforeCreate should have been called');
56+
assert.equal(lifecycle.afterCreate.callCount, 1, 'afterCreate should have been called');
57+
assert.equal(lifecycle.beforeInject.callCount, 0, 'beforeInject should not have been called');
58+
assert.equal(lifecycle.afterInject.callCount, 0, 'afterInject should not have been called');
59+
assert.equal(lifecycle.serialize.callCount, 1, 'serialize should have been called');
60+
assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called');
61+
assert.isUndefined(DS.get('post', 5));
62+
63+
done();
64+
} catch (e) {
65+
done(e);
66+
}
67+
}, 30);
68+
} catch (e) {
69+
done(e);
70+
}
71+
}, 30);
72+
});
73+
it('should work with the upsert option', function (done) {
74+
$httpBackend.expectPUT('http://test.angular-cache.com/posts/5').respond(200, p1);
75+
76+
DS.create('post', { author: 'John', age: 30, id: 5 }).then(function (post) {
77+
assert.deepEqual(angular.toJson(post), angular.toJson(p1), 'post 5 should have been created');
78+
}, function (err) {
79+
console.error(err.stack);
80+
fail('should not have rejected');
81+
});
82+
83+
setTimeout(function () {
84+
try {
85+
$httpBackend.flush();
86+
$httpBackend.expectPOST('http://test.angular-cache.com/posts').respond(200, p2);
87+
88+
setTimeout(function () {
89+
try {
90+
DS.create('post', { author: 'Sue', age: 70, id: 6 }, { upsert: false }).then(function (post) {
91+
assert.deepEqual(angular.toJson(post), angular.toJson(p2), 'post 6 should have been created');
92+
}, function (err) {
93+
console.error(err.stack);
94+
fail('should not have rejected');
95+
});
96+
97+
setTimeout(function () {
98+
try {
99+
$httpBackend.flush();
100+
101+
setTimeout(function () {
102+
try {
103+
assert.equal(lifecycle.beforeUpdate.callCount, 1, 'beforeUpdate should have been called');
104+
assert.equal(lifecycle.afterUpdate.callCount, 1, 'afterUpdate should have been called');
105+
assert.equal(lifecycle.beforeCreate.callCount, 1, 'beforeCreate should have been called');
106+
assert.equal(lifecycle.afterCreate.callCount, 1, 'afterCreate should have been called');
107+
assert.equal(lifecycle.beforeInject.callCount, 2, 'beforeInject should have been called twice');
108+
assert.equal(lifecycle.afterInject.callCount, 2, 'afterInject should have been called twice');
109+
assert.equal(lifecycle.serialize.callCount, 2, 'serialize should have been called twice');
110+
assert.equal(lifecycle.deserialize.callCount, 2, 'deserialize should have been called twice');
111+
assert.isDefined(DS.get('post', 5));
112+
assert.isDefined(DS.get('post', 6));
113+
114+
done();
115+
} catch (e) {
116+
done(e);
117+
}
118+
}, 30);
119+
} catch (e) {
120+
done(e);
121+
}
122+
}, 30);
123+
} catch (e) {
124+
done(e);
125+
}
126+
}, 30);
127+
} catch (e) {
128+
done(e);
129+
}
130+
}, 30);
131+
});
132+
it('should create an item that includes relations, save them to the server and inject the results', function (done) {
133+
var payload = {
134+
id: 99,
135+
name: 'Sally',
136+
profile: {
137+
id: 999,
138+
userId: 99,
139+
email: 'sally@test.com'
140+
}
141+
};
142+
143+
$httpBackend.expectPOST('http://test.angular-cache.com/user').respond(200, payload);
144+
145+
DS.create('user', {
146+
name: 'Sally',
147+
profile: {
148+
email: 'sally@test.com'
149+
}
150+
}, {
151+
findBelongsTo: true
152+
}).then(function (user) {
153+
assert.deepEqual(user.id, payload.id, 'user should have been created');
154+
155+
DS.find('user', 99); // should not trigger another http request
156+
}, function (err) {
157+
console.error(err.stack);
158+
fail('should not have rejected');
159+
});
160+
161+
setTimeout(function () {
162+
try {
163+
$httpBackend.flush();
164+
165+
setTimeout(function () {
166+
try {
167+
assert.equal(lifecycle.beforeCreate.callCount, 1, 'beforeCreate should have been called twice');
168+
assert.equal(lifecycle.afterCreate.callCount, 1, 'afterCreate should have been called twice');
169+
assert.equal(lifecycle.beforeInject.callCount, 2, 'beforeInject should have been called twice');
170+
assert.equal(lifecycle.afterInject.callCount, 2, 'afterInject should have been called twice');
171+
assert.equal(lifecycle.serialize.callCount, 1, 'serialize should have been called');
172+
assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called');
173+
assert.deepEqual(DS.get('user', 99).id, payload.id);
174+
assert.isObject(DS.get('user', 99).profile);
175+
assert.deepEqual(DS.get('profile', 999).id, 999);
176+
assert.isObject(DS.get('profile', 999).user);
177+
178+
done();
179+
} catch (e) {
180+
done(e);
181+
}
182+
}, 30);
183+
} catch (e) {
184+
done(e);
185+
}
186+
}, 30);
187+
});
188+
it('should handle nested resources', function (done) {
189+
var testComment = {
190+
id: 5,
191+
content: 'test',
192+
approvedBy: 4
193+
};
194+
var testComment2 = {
195+
id: 6,
196+
content: 'test',
197+
approvedBy: 4
198+
};
199+
$httpBackend.expectPOST('http://test.angular-cache.com/user/4/comment').respond(200, testComment);
200+
201+
DS.create('comment', {
202+
content: 'test',
203+
approvedBy: 4
204+
}).then(function (comment) {
205+
assert.deepEqual(angular.toJson(comment), angular.toJson(testComment));
206+
assert.deepEqual(angular.toJson(comment), angular.toJson(DS.get('comment', 5)));
207+
}, function () {
208+
fail('Should not have failed!');
209+
});
210+
211+
setTimeout(function () {
212+
try {
213+
$httpBackend.flush();
214+
$httpBackend.expectPOST('http://test.angular-cache.com/user/4/comment').respond(200, testComment2);
215+
216+
setTimeout(function () {
217+
try {
218+
DS.create('comment', {
219+
content: 'test'
220+
}, {
221+
params: {
222+
approvedBy: 4
223+
}
224+
}).then(function (comment) {
225+
assert.deepEqual(angular.toJson(comment), angular.toJson(testComment2));
226+
assert.deepEqual(angular.toJson(comment), angular.toJson(DS.get('comment', 6)));
227+
}, function () {
228+
fail('Should not have failed!');
229+
});
230+
231+
setTimeout(function () {
232+
try {
233+
$httpBackend.flush();
234+
$httpBackend.expectPOST('http://test.angular-cache.com/comment').respond(200, testComment2);
235+
236+
setTimeout(function () {
237+
try {
238+
DS.create('comment', {
239+
content: 'test',
240+
approvedBy: 4
241+
}, {
242+
params: {
243+
approvedBy: false
244+
}
245+
}).then(function (comment) {
246+
assert.deepEqual(angular.toJson(comment), angular.toJson(testComment2));
247+
assert.deepEqual(comment, DS.get('comment', 6));
248+
}, function () {
249+
fail('Should not have failed!');
250+
});
251+
setTimeout(function () {
252+
try {
253+
$httpBackend.flush();
254+
done();
255+
} catch (e) {
256+
done(e);
257+
}
258+
}, 30);
259+
} catch (e) {
260+
done(e);
261+
}
262+
}, 30);
263+
} catch (e) {
264+
done(e);
265+
}
266+
}, 30);
267+
} catch (e) {
268+
done(e);
269+
}
270+
}, 30);
271+
} catch (e) {
272+
done(e);
273+
}
274+
}, 30);
275+
});
276+
it('should find inverse links', function (done) {
277+
DS.inject('organization', {
278+
id: 77
279+
});
280+
281+
$httpBackend.expectPOST('http://test.angular-cache.com/organization/77/user').respond(200, {
282+
organizationId: 77,
283+
id: 88
284+
});
285+
286+
DS.create('user', {
287+
organizationId: 77,
288+
id: 88
289+
}, { upsert: false, findBelongsTo: true }).then(function (user) {
290+
var organization = DS.link('organization', 77, ['user']);
291+
assert.isArray(organization.users);
292+
assert.equal(1, organization.users.length);
293+
assert.isObject(user.organization);
294+
assert.isTrue(user.organization === organization);
295+
assert.isTrue(user === organization.users[0]);
296+
done();
297+
}, function () {
298+
done('Should not have succeeded!');
299+
});
300+
301+
setTimeout(function () {
302+
try {
303+
$httpBackend.flush();
304+
} catch (e) {
305+
done(e);
306+
}
307+
}, 30);
308+
});
309+
// Not yet implemented in js-data
310+
//it('should eager inject', function () {
311+
// $httpBackend.expectPOST('http://test.angular-cache.com/organization/77/user').respond(200, {
312+
// organizationId: 77,
313+
// id: 88
314+
// });
315+
//
316+
// var eagerUser;
317+
//
318+
// DS.create('user', {
319+
// organizationId: 77
320+
// }, { eagerInject: true }).then(function (user) {
321+
// assert.equal(user.id, 88);
322+
// assert.isTrue(eagerUser === user);
323+
// assert.isTrue(DS.filter('user')[0] === user);
324+
// }, function () {
325+
// fail('Should not have succeeded!');
326+
// });
327+
//
328+
// $rootScope.$apply();
329+
//
330+
// eagerUser = DS.filter('user')[0];
331+
// assert.isDefined(eagerUser);
332+
// assert.equal(eagerUser.organizationId, 77);
333+
// assert.notEqual(eagerUser.id, 88);
334+
//
335+
// $httpBackend.flush();
336+
//});
337+
});
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
describe('DS.destroy', function () {
2+
beforeEach(startInjector);
3+
4+
it('should delete an item from the data store', function (done) {
5+
$httpBackend.expectDELETE('http://test.angular-cache.com/posts/5').respond(200, 5);
6+
7+
DS.inject('post', p1);
8+
9+
DS.destroy('post', 5).then(function (id) {
10+
try {
11+
assert.equal(id, 5, 'post 5 should have been deleted');
12+
assert.equal(lifecycle.beforeDestroy.callCount, 1, 'beforeDestroy should have been called');
13+
assert.equal(lifecycle.afterDestroy.callCount, 1, 'afterDestroy should have been called');
14+
assert.isUndefined(DS.get('post', 5));
15+
assert.equal(DS.lastModified('post', 5), 0);
16+
assert.equal(DS.lastSaved('post', 5), 0);
17+
done();
18+
} catch (err) {
19+
done(err);
20+
}
21+
}, function (err) {
22+
console.error(err.stack);
23+
done('should not have rejected');
24+
});
25+
26+
setTimeout(function () {
27+
try {
28+
$httpBackend.flush();
29+
} catch (e) {
30+
done(e);
31+
}
32+
}, 30);
33+
});
34+
it('should handle nested resources', function (done) {
35+
var testComment = {
36+
id: 5,
37+
content: 'test'
38+
};
39+
var testComment2 = {
40+
id: 6,
41+
content: 'test',
42+
approvedBy: 4
43+
};
44+
45+
DS.inject('comment', testComment);
46+
47+
$httpBackend.expectDELETE('http://test.angular-cache.com/user/4/comment/5').respond(204);
48+
49+
DS.destroy('comment', 5, {
50+
params: {
51+
approvedBy: 4
52+
}
53+
}).then(null, function () {
54+
done('Should not have failed!');
55+
});
56+
57+
setTimeout(function () {
58+
try {
59+
$httpBackend.flush();
60+
61+
$httpBackend.expectDELETE('http://test.angular-cache.com/user/4/comment/6').respond(204);
62+
63+
DS.inject('comment', testComment2);
64+
65+
DS.destroy('comment', 6, {
66+
bypassCache: true
67+
}).then(null, function () {
68+
done('Should not have failed!');
69+
});
70+
71+
setTimeout(function () {
72+
try {
73+
$httpBackend.flush();
74+
75+
setTimeout(function () {
76+
try {
77+
$httpBackend.expectDELETE('http://test.angular-cache.com/comment/6').respond(204);
78+
DS.inject('comment', testComment2);
79+
DS.destroy('comment', 6, {
80+
params: {
81+
approvedBy: false
82+
}
83+
}).then(null, function (err) {
84+
console.log(err.stack);
85+
done('Should not have failed!');
86+
});
87+
88+
setTimeout(function () {
89+
try {
90+
$httpBackend.flush();
91+
done();
92+
} catch (e) {
93+
done(e);
94+
}
95+
}, 30);
96+
} catch (e) {
97+
done(e);
98+
}
99+
}, 30);
100+
} catch (e) {
101+
done(e);
102+
}
103+
}, 30);
104+
} catch (e) {
105+
done(e);
106+
}
107+
}, 30);
108+
});
109+
// not yet implemented in js-data
110+
//it('should eager eject', function (done) {
111+
// $httpBackend.expectDELETE('http://test.angular-cache.com/posts/5').respond(200, 5);
112+
//
113+
// DS.inject('post', p1);
114+
//
115+
// DS.destroy('post', 5, { eagerEject: true }).then(function (id) {
116+
// assert.equal(id, 5, 'post 5 should have been deleted');
117+
// }, function (err) {
118+
// console.error(err.stack);
119+
// fail('should not have rejected');
120+
// });
121+
//
122+
// $rootScope.$apply();
123+
//
124+
// assert.isUndefined(DS.get('post', 5));
125+
//
126+
// setTimeout(function () {
127+
// try {
128+
// $httpBackend.flush();
129+
//
130+
// setTimeout(function () {
131+
// try {
132+
// assert.equal(lifecycle.beforeDestroy.callCount, 1, 'beforeDestroy should have been called');
133+
// assert.equal(lifecycle.afterDestroy.callCount, 1, 'afterDestroy should have been called');
134+
// assert.isUndefined(DS.get('post', 5));
135+
// assert.equal(DS.lastModified('post', 5), 0);
136+
// assert.equal(DS.lastSaved('post', 5), 0);
137+
//
138+
// done();
139+
// } catch (e) {
140+
// done(e);
141+
// }
142+
// });
143+
// } catch (e) {
144+
// done(e);
145+
// }
146+
// }, 30);
147+
//});
148+
});
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
describe('DS.destroyAll', function () {
2+
beforeEach(startInjector);
3+
4+
it('should query the server for a collection', function (done) {
5+
$httpBackend.expectDELETE('http://test.angular-cache.com/posts?where=%7B%22age%22:33%7D').respond(200);
6+
7+
DS.inject('post', p1);
8+
DS.inject('post', p2);
9+
DS.inject('post', p3);
10+
DS.inject('post', p4);
11+
DS.inject('post', p5);
12+
13+
DS.destroyAll('post', { where: { age: 33 } }).then(null, function (err) {
14+
console.error(err.stack);
15+
done('Should not have rejected!');
16+
});
17+
18+
setTimeout(function () {
19+
try {
20+
$httpBackend.flush();
21+
22+
setTimeout(function () {
23+
try {
24+
assert.isDefined(DS.get('post', 5));
25+
assert.isDefined(DS.get('post', 6));
26+
assert.isDefined(DS.get('post', 7));
27+
assert.isUndefined(DS.get('post', 8));
28+
assert.isUndefined(DS.get('post', 9));
29+
30+
$httpBackend.expectDELETE('http://test.angular-cache.com/posts').respond(200);
31+
32+
DS.inject('post', p1);
33+
DS.inject('post', p2);
34+
DS.inject('post', p3);
35+
DS.inject('post', p4);
36+
DS.inject('post', p5);
37+
38+
DS.destroyAll('post', {}).then(null, function (err) {
39+
console.error(err.stack);
40+
done('Should not have rejected!');
41+
});
42+
43+
setTimeout(function () {
44+
try {
45+
$httpBackend.flush();
46+
47+
setTimeout(function () {
48+
try {
49+
assert.deepEqual(DS.filter('post', {}), [], 'The posts should not be in the store yet');
50+
51+
done();
52+
} catch (e) {
53+
done(e);
54+
}
55+
});
56+
} catch (e) {
57+
done(e);
58+
}
59+
}, 30);
60+
} catch (e) {
61+
done(e);
62+
}
63+
});
64+
} catch (e) {
65+
done(e);
66+
}
67+
}, 30);
68+
});
69+
it('should handle nested resources', function (done) {
70+
$httpBackend.expectDELETE('http://test.angular-cache.com/user/4/comment?content=test').respond(204);
71+
72+
DS.destroyAll('comment', {
73+
content: 'test'
74+
}, {
75+
params: {
76+
approvedBy: 4
77+
}
78+
}).then(function () {
79+
}, function (err) {
80+
console.log(err);
81+
fail('Should not have failed!');
82+
});
83+
84+
setTimeout(function () {
85+
try {
86+
$httpBackend.flush();
87+
88+
setTimeout(function () {
89+
try {
90+
$httpBackend.expectDELETE('http://test.angular-cache.com/comment?content=test').respond(204);
91+
92+
DS.destroyAll('comment', {
93+
content: 'test'
94+
}).then(function () {
95+
}, function (err) {
96+
console.log(err);
97+
fail('Should not have failed!');
98+
});
99+
100+
setTimeout(function () {
101+
try {
102+
$httpBackend.flush();
103+
104+
setTimeout(function () {
105+
try {
106+
$httpBackend.expectDELETE('http://test.angular-cache.com/comment?content=test').respond(204);
107+
108+
DS.destroyAll('comment', {
109+
content: 'test'
110+
}, {
111+
params: {
112+
approvedBy: false
113+
}
114+
}).then(function () {
115+
}, function (err) {
116+
console.log(err);
117+
fail('Should not have failed!');
118+
});
119+
120+
setTimeout(function () {
121+
try {
122+
$httpBackend.flush();
123+
124+
setTimeout(function () {
125+
try {
126+
done();
127+
} catch (e) {
128+
done(e);
129+
}
130+
});
131+
} catch (e) {
132+
done(e);
133+
}
134+
}, 30);
135+
} catch (e) {
136+
done(e);
137+
}
138+
});
139+
} catch (e) {
140+
done(e);
141+
}
142+
}, 30);
143+
} catch (e) {
144+
done(e);
145+
}
146+
});
147+
} catch (e) {
148+
done(e);
149+
}
150+
}, 30);
151+
});
152+
});
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
describe('DS.find', function () {
2+
beforeEach(startInjector);
3+
4+
it('should get an item from the server', function (done) {
5+
$httpBackend.expectGET('http://test.angular-cache.com/posts/5').respond(200, p1);
6+
7+
DS.find('post', 5).then(function (post) {
8+
assert.deepEqual(angular.toJson(post), angular.toJson(p1));
9+
}, function (err) {
10+
console.error(err.stack);
11+
fail('Should not have rejected!');
12+
});
13+
14+
assert.isUndefined(DS.get('post', 5), 'The post should not be in the store yet');
15+
16+
// Should have no effect because there is already a pending query
17+
DS.find('post', 5).then(function (post) {
18+
assert.deepEqual(angular.toJson(post), angular.toJson(p1));
19+
}, function (err) {
20+
console.error(err.stack);
21+
fail('Should not have rejected!');
22+
});
23+
24+
setTimeout(function () {
25+
try {
26+
$httpBackend.flush();
27+
28+
setTimeout(function () {
29+
try {
30+
assert.deepEqual(angular.toJson(DS.get('post', 5)), angular.toJson(p1), 'The post is now in the store');
31+
assert.isNumber(DS.lastModified('post', 5));
32+
assert.isNumber(DS.lastSaved('post', 5));
33+
34+
// Should not make a request because the request was already completed
35+
DS.find('post', 5).then(function (post) {
36+
assert.deepEqual(angular.toJson(post), angular.toJson(p1));
37+
}, function (err) {
38+
console.error(err.stack);
39+
fail('Should not have rejected!');
40+
});
41+
42+
$httpBackend.expectGET('http://test.angular-cache.com/posts/5').respond(200, p1);
43+
44+
// Should make a request because bypassCache is set to true
45+
DS.find('post', 5, { bypassCache: true }).then(function (post) {
46+
assert.deepEqual(angular.toJson(post), angular.toJson(p1));
47+
}, function (err) {
48+
console.error(err.stack);
49+
fail('Should not have rejected!');
50+
});
51+
52+
setTimeout(function () {
53+
try {
54+
$httpBackend.flush();
55+
56+
setTimeout(function () {
57+
try {
58+
assert.equal(lifecycle.beforeInject.callCount, 2, 'beforeInject should have been called');
59+
assert.equal(lifecycle.afterInject.callCount, 2, 'afterInject should have been called');
60+
assert.equal(lifecycle.serialize.callCount, 0, 'serialize should have been called');
61+
assert.equal(lifecycle.deserialize.callCount, 2, 'deserialize should have been called');
62+
63+
done();
64+
} catch (e) {
65+
done(e);
66+
}
67+
});
68+
} catch (e) {
69+
done(e);
70+
}
71+
}, 30);
72+
} catch (e) {
73+
done(e);
74+
}
75+
});
76+
} catch (e) {
77+
done(e);
78+
}
79+
}, 30);
80+
});
81+
it('should get an item from the server but not store it if cacheResponse is false', function (done) {
82+
$httpBackend.expectGET('http://test.angular-cache.com/posts/5').respond(200, p1);
83+
84+
DS.find('post', 5, { cacheResponse: false }).then(function (post) {
85+
assert.deepEqual(angular.toJson(post), angular.toJson(p1));
86+
}, function (err) {
87+
console.error(err.stack);
88+
fail('Should not have rejected!');
89+
});
90+
91+
setTimeout(function () {
92+
try {
93+
$httpBackend.flush();
94+
95+
setTimeout(function () {
96+
try {
97+
assert.isUndefined(DS.get('post', 5), 'The post should not have been injected into the store');
98+
assert.equal(lifecycle.beforeInject.callCount, 0, 'beforeInject should have been called');
99+
assert.equal(lifecycle.afterInject.callCount, 0, 'afterInject should have been called');
100+
assert.equal(lifecycle.serialize.callCount, 0, 'serialize should have been called');
101+
assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called');
102+
103+
done();
104+
} catch (e) {
105+
done(e);
106+
}
107+
});
108+
} catch (e) {
109+
done(e);
110+
}
111+
}, 30);
112+
});
113+
it('should correctly propagate errors', function (done) {
114+
$httpBackend.expectGET('http://test.angular-cache.com/posts/5').respond(404, 'Not Found');
115+
116+
DS.find('post', 5).then(function () {
117+
done('Should not have succeeded!');
118+
}, function (err) {
119+
assert.equal(err.data, 'Not Found');
120+
done();
121+
});
122+
123+
setTimeout(function () {
124+
try {
125+
$httpBackend.flush();
126+
} catch (e) {
127+
console.log(e);
128+
done(e);
129+
}
130+
}, 30);
131+
});
132+
it('should handle nested resources', function (done) {
133+
var testComment = {
134+
id: 5,
135+
content: 'test',
136+
approvedBy: 4
137+
};
138+
$httpBackend.expectGET('http://test.angular-cache.com/user/4/comment/5').respond(200, testComment);
139+
140+
DS.find('comment', 5, {
141+
params: {
142+
approvedBy: 4
143+
}
144+
}).then(function (comment) {
145+
assert.deepEqual(angular.toJson(comment), angular.toJson(testComment));
146+
assert.deepEqual(angular.toJson(comment), angular.toJson(DS.get('comment', 5)));
147+
}, function () {
148+
fail('Should not have failed!');
149+
});
150+
151+
setTimeout(function () {
152+
try {
153+
$httpBackend.flush();
154+
155+
setTimeout(function () {
156+
try {
157+
$httpBackend.expectGET('http://test.angular-cache.com/user/4/comment/5').respond(200, testComment);
158+
159+
DS.find('comment', 5, {
160+
bypassCache: true
161+
}).then(function (comment) {
162+
assert.deepEqual(angular.toJson(comment), angular.toJson(testComment));
163+
assert.deepEqual(angular.toJson(comment), angular.toJson(DS.get('comment', 5)));
164+
}, function () {
165+
fail('Should not have failed!');
166+
});
167+
168+
setTimeout(function () {
169+
try {
170+
$httpBackend.flush();
171+
172+
setTimeout(function () {
173+
try {
174+
$httpBackend.expectGET('http://test.angular-cache.com/comment/5').respond(200, testComment);
175+
176+
DS.find('comment', 5, {
177+
bypassCache: true,
178+
params: {
179+
approvedBy: false
180+
}
181+
}).then(function (comment) {
182+
assert.deepEqual(angular.toJson(comment), angular.toJson(testComment));
183+
assert.deepEqual(angular.toJson(comment), angular.toJson(DS.get('comment', 5)));
184+
}, function () {
185+
fail('Should not have failed!');
186+
});
187+
188+
setTimeout(function () {
189+
try {
190+
$httpBackend.flush();
191+
192+
setTimeout(function () {
193+
try {
194+
$httpBackend.expectGET('http://test.angular-cache.com/organization/14/user/19/comment/19').respond(200, comment19);
195+
196+
DS.find('comment', 19, {
197+
bypassCache: true,
198+
params: {
199+
approvedBy: 19,
200+
organizationId: 14
201+
}
202+
}).then(function (comment) {
203+
assert.equal(comment.id, comment19.id);
204+
assert.equal(comment.id, DS.get('comment', 19).id);
205+
}, function () {
206+
fail('Should not have failed!');
207+
});
208+
209+
setTimeout(function () {
210+
try {
211+
$httpBackend.flush();
212+
done();
213+
} catch (e) {
214+
done(e);
215+
}
216+
}, 30);
217+
} catch (e) {
218+
done(e);
219+
}
220+
});
221+
} catch (e) {
222+
done(e);
223+
}
224+
}, 30);
225+
} catch (e) {
226+
done(e);
227+
}
228+
});
229+
} catch (e) {
230+
done(e);
231+
}
232+
}, 30);
233+
} catch (e) {
234+
done(e);
235+
}
236+
});
237+
} catch (e) {
238+
done(e);
239+
}
240+
}, 30);
241+
});
242+
});
Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
1+
describe('DS.findAll', function () {
2+
3+
beforeEach(startInjector);
4+
5+
it('should query the server for a collection', function (done) {
6+
$httpBackend.expectGET(/http:\/\/test\.angular-cache\.com\/posts\??/).respond(200, [p1, p2, p3, p4]);
7+
8+
DS.findAll('post', {}).then(function (data) {
9+
assert.deepEqual(angular.toJson(data), angular.toJson([p1, p2, p3, p4]));
10+
}, function (err) {
11+
console.error(err.stack);
12+
fail('Should not have rejected!');
13+
});
14+
15+
assert.deepEqual(DS.filter('post', {}), [], 'The posts should not be in the store yet');
16+
17+
// Should have no effect because there is already a pending query
18+
DS.findAll('post', {}).then(function (data) {
19+
assert.deepEqual(angular.toJson(data), angular.toJson([p1, p2, p3, p4]));
20+
}, function (err) {
21+
console.error(err.stack);
22+
fail('Should not have rejected!');
23+
});
24+
25+
setTimeout(function () {
26+
try {
27+
$httpBackend.flush();
28+
29+
setTimeout(function () {
30+
try {
31+
assert.deepEqual(angular.toJson(DS.filter('post', {})), angular.toJson([p1, p2, p3, p4]), 'The posts are now in the store');
32+
assert.isNumber(DS.lastModified('post', 5));
33+
assert.isNumber(DS.lastSaved('post', 5));
34+
DS.find('post', p1.id); // should not trigger another XHR
35+
36+
37+
// Should not make a request because the request was already completed
38+
DS.findAll('post', {}).then(function (data) {
39+
assert.deepEqual(angular.toJson(data), angular.toJson([p1, p2, p3, p4]));
40+
}, function (err) {
41+
console.error(err.stack);
42+
fail('Should not have rejected!');
43+
});
44+
45+
$httpBackend.expectGET(/http:\/\/test\.angular-cache\.com\/posts\??/).respond(200, [p1, p2, p3, p4]);
46+
47+
// Should make a request because bypassCache is set to true
48+
DS.findAll('post', {}, { bypassCache: true }).then(function (data) {
49+
assert.deepEqual(angular.toJson(data), angular.toJson([p1, p2, p3, p4]));
50+
}, function (err) {
51+
console.error(err.stack);
52+
fail('Should not have rejected!');
53+
});
54+
55+
setTimeout(function () {
56+
try {
57+
$httpBackend.flush();
58+
59+
setTimeout(function () {
60+
try {
61+
assert.equal(lifecycle.beforeInject.callCount, 2, 'beforeInject should have been called');
62+
assert.equal(lifecycle.afterInject.callCount, 2, 'afterInject should have been called');
63+
assert.equal(lifecycle.serialize.callCount, 0, 'serialize should have been called');
64+
assert.equal(lifecycle.deserialize.callCount, 2, 'deserialize should have been called');
65+
done();
66+
} catch (e) {
67+
done(e);
68+
}
69+
});
70+
} catch (e) {
71+
done(e);
72+
}
73+
}, 30);
74+
} catch (e) {
75+
done(e);
76+
}
77+
});
78+
} catch (e) {
79+
done(e);
80+
}
81+
}, 30);
82+
});
83+
it('should query the server for a collection but not store the data if cacheResponse is false', function (done) {
84+
$httpBackend.expectGET(/http:\/\/test\.angular-cache\.com\/posts\??/).respond(200, [p1, p2, p3, p4]);
85+
86+
DS.findAll('post', {}, { cacheResponse: false }).then(function (data) {
87+
assert.deepEqual(angular.toJson(data), angular.toJson([p1, p2, p3, p4]));
88+
}, function (err) {
89+
console.error(err.stack);
90+
fail('Should not have rejected!');
91+
});
92+
93+
setTimeout(function () {
94+
try {
95+
$httpBackend.flush();
96+
97+
setTimeout(function () {
98+
try {
99+
assert.deepEqual(angular.toJson(DS.filter('post', {})), angular.toJson([]), 'The posts should not have been injected into the store');
100+
101+
assert.equal(lifecycle.beforeInject.callCount, 0, 'beforeInject should have been called');
102+
assert.equal(lifecycle.afterInject.callCount, 0, 'afterInject should have been called');
103+
assert.equal(lifecycle.serialize.callCount, 0, 'serialize should have been called');
104+
assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called');
105+
106+
done();
107+
} catch (e) {
108+
done(e);
109+
}
110+
});
111+
} catch (e) {
112+
done(e);
113+
}
114+
}, 30);
115+
});
116+
it('should correctly propagate errors', function (done) {
117+
$httpBackend.expectGET(/http:\/\/test\.angular-cache\.com\/posts\??/).respond(404, 'Not Found');
118+
119+
DS.findAll('post', {}).then(function () {
120+
done('Should not have succeeded!');
121+
}, function (err) {
122+
assert.equal(err.data, 'Not Found');
123+
done();
124+
});
125+
126+
setTimeout(function () {
127+
try {
128+
$httpBackend.flush();
129+
} catch (e) {
130+
done(e);
131+
}
132+
}, 30);
133+
});
134+
it('"params" argument is optional', function (done) {
135+
$httpBackend.expectGET(/http:\/\/test\.angular-cache\.com\/posts\??/).respond(200, [p1, p2, p3, p4]);
136+
137+
DS.findAll('post').then(function (data) {
138+
assert.deepEqual(angular.toJson(data), angular.toJson([p1, p2, p3, p4]));
139+
}, function (err) {
140+
console.error(err.message);
141+
fail('Should not have rejected!');
142+
});
143+
144+
setTimeout(function () {
145+
try {
146+
$httpBackend.flush();
147+
148+
setTimeout(function () {
149+
try {
150+
assert.deepEqual(angular.toJson(DS.filter('post', {})), angular.toJson([p1, p2, p3, p4]), 'The posts are now in the store');
151+
152+
assert.equal(lifecycle.beforeInject.callCount, 1 , 'beforeInject should have been called');
153+
assert.equal(lifecycle.afterInject.callCount, 1, 'afterInject should have been called');
154+
assert.equal(lifecycle.serialize.callCount, 0, 'serialize should have been called');
155+
assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called');
156+
157+
done();
158+
} catch (e) {
159+
done(e);
160+
}
161+
});
162+
} catch (e) {
163+
done(e);
164+
}
165+
}, 30);
166+
});
167+
it('"params"', function (done) {
168+
$httpBackend.expectGET('http://test.angular-cache.com/posts?where=%7B%22author%22:%22Adam%22%7D').respond(200, [p4, p5]);
169+
170+
var params = {
171+
where: {
172+
author: 'Adam'
173+
}
174+
};
175+
DS.findAll('post', params).then(function (data) {
176+
assert.deepEqual(angular.toJson(data), angular.toJson([p4, p5]));
177+
}, function (err) {
178+
console.error(err.message);
179+
fail('Should not have rejected!');
180+
});
181+
182+
setTimeout(function () {
183+
try {
184+
$httpBackend.flush();
185+
186+
setTimeout(function () {
187+
try {
188+
assert.deepEqual(angular.toJson(DS.filter('post', params)), angular.toJson([p4, p5]), 'The posts are now in the store');
189+
assert.deepEqual(angular.toJson(DS.filter('post', {
190+
where: {
191+
id: {
192+
'>': 8
193+
}
194+
}
195+
})), angular.toJson([p5]), 'The posts are now in the store');
196+
197+
assert.equal(lifecycle.beforeInject.callCount, 1, 'beforeInject should have been called');
198+
assert.equal(lifecycle.afterInject.callCount, 1, 'afterInject should have been called');
199+
assert.equal(lifecycle.serialize.callCount, 0, 'serialize should have been called');
200+
assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called');
201+
202+
done();
203+
} catch (e) {
204+
done(e);
205+
}
206+
});
207+
} catch (e) {
208+
done(e);
209+
}
210+
}, 30);
211+
});
212+
it('should return already injected items', function (done) {
213+
var u1 = {
214+
id: 1,
215+
name: 'John'
216+
},
217+
u2 = {
218+
id: 2,
219+
name: 'Sally'
220+
};
221+
222+
DS.defineResource({
223+
name: 'person',
224+
endpoint: 'users',
225+
methods: {
226+
fullName: function () {
227+
return this.first + ' ' + this.last;
228+
}
229+
}
230+
});
231+
232+
$httpBackend.expectGET(/http:\/\/test\.angular-cache\.com\/users\??/).respond(200, [u1, u2]);
233+
234+
DS.findAll('person').then(function (data) {
235+
assert.deepEqual(angular.toJson(data), angular.toJson([
236+
DSUtils.deepMixIn(new DS.definitions.person[DS.definitions.person.class](), u1),
237+
DSUtils.deepMixIn(new DS.definitions.person[DS.definitions.person.class](), u2)
238+
]));
239+
angular.forEach(data, function (person) {
240+
assert.isTrue(person instanceof DS.definitions.person[DS.definitions.person.class], 'should be an instance of User');
241+
});
242+
}, function (err) {
243+
console.error(err.message);
244+
fail('Should not have rejected!');
245+
});
246+
247+
setTimeout(function () {
248+
try {
249+
$httpBackend.flush();
250+
251+
setTimeout(function () {
252+
try {
253+
assert.deepEqual(angular.toJson(DS.filter('person')), angular.toJson([
254+
DSUtils.deepMixIn(new DS.definitions.person[DS.definitions.person.class](), u1),
255+
DSUtils.deepMixIn(new DS.definitions.person[DS.definitions.person.class](), u2)
256+
]), 'The users are now in the store');
257+
258+
assert.equal(lifecycle.beforeInject.callCount, 1, 'beforeInject should have been called');
259+
assert.equal(lifecycle.afterInject.callCount, 1, 'afterInject should have been called');
260+
assert.equal(lifecycle.serialize.callCount, 0, 'serialize should have been called');
261+
assert.equal(lifecycle.deserialize.callCount, 1, 'deserialize should have been called');
262+
263+
done();
264+
} catch (e) {
265+
done(e);
266+
}
267+
});
268+
} catch (e) {
269+
done(e);
270+
}
271+
}, 30);
272+
});
273+
it('should handle nested resources', function (done) {
274+
var testComment = {
275+
id: 5,
276+
content: 'test',
277+
approvedBy: 4
278+
};
279+
var testComment2 = {
280+
id: 6,
281+
content: 'test',
282+
approvedBy: 4
283+
};
284+
$httpBackend.expectGET('http://test.angular-cache.com/user/4/comment?content=test').respond(200, [testComment, testComment2]);
285+
286+
DS.findAll('comment', {
287+
content: 'test'
288+
}, {
289+
params: {
290+
approvedBy: 4
291+
}
292+
}).then(function (comments) {
293+
assert.deepEqual(angular.toJson(comments), angular.toJson([testComment, testComment2]));
294+
assert.deepEqual(angular.toJson(comments), angular.toJson(DS.filter('comment', {
295+
content: 'test'
296+
})));
297+
done();
298+
}, function () {
299+
done('Should not have failed!');
300+
});
301+
302+
setTimeout(function () {
303+
try {
304+
$httpBackend.flush();
305+
} catch (e) {
306+
done(e);
307+
}
308+
}, 30);
309+
});
310+
it('should handle nested resources 2', function (done) {
311+
var testComment = {
312+
id: 5,
313+
content: 'test',
314+
approvedBy: 4
315+
};
316+
var testComment2 = {
317+
id: 6,
318+
content: 'test',
319+
approvedBy: 4
320+
};
321+
322+
$httpBackend.expectGET('http://test.angular-cache.com/comment?content=test').respond(200, [testComment, testComment2]);
323+
324+
DS.findAll('comment', {
325+
content: 'test'
326+
}, {
327+
bypassCache: true
328+
}).then(function (comments) {
329+
assert.deepEqual(angular.toJson(comments), angular.toJson([testComment, testComment2]));
330+
assert.deepEqual(angular.toJson(comments), angular.toJson(DS.filter('comment', {
331+
content: 'test'
332+
})));
333+
done();
334+
}, function () {
335+
done('Should not have failed!');
336+
});
337+
338+
setTimeout(function () {
339+
try {
340+
$httpBackend.flush();
341+
} catch (e) {
342+
done(e);
343+
}
344+
}, 30);
345+
});
346+
it('should handle nested resources 3', function (done) {
347+
var testComment = {
348+
id: 5,
349+
content: 'test',
350+
approvedBy: 4
351+
};
352+
var testComment2 = {
353+
id: 6,
354+
content: 'test',
355+
approvedBy: 4
356+
};
357+
358+
DS.ejectAll('comment');
359+
360+
$httpBackend.expectGET('http://test.angular-cache.com/comment?content=test').respond(200, [testComment, testComment2]);
361+
362+
DS.findAll('comment', {
363+
content: 'test'
364+
}, {
365+
bypassCache: true,
366+
params: {
367+
approvedBy: false
368+
}
369+
}).then(function (comments) {
370+
assert.deepEqual(angular.toJson(comments), angular.toJson([testComment, testComment2]));
371+
assert.deepEqual(angular.toJson(comments), angular.toJson(DS.filter('comment', {
372+
content: 'test'
373+
})));
374+
done();
375+
}, function () {
376+
done('Should not have failed!');
377+
});
378+
379+
setTimeout(function () {
380+
try {
381+
$httpBackend.flush();
382+
} catch (e) {
383+
done(e);
384+
}
385+
}, 30);
386+
});
387+
});

0 commit comments

Comments
 (0)
Please sign in to comment.