kojac 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +7 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +158 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +69 -0
  7. data/Rakefile +27 -0
  8. data/app/assets/javascripts/can_extensions.js +45 -0
  9. data/app/assets/javascripts/kojac.js +1230 -0
  10. data/app/assets/javascripts/kojac_canjs.js +191 -0
  11. data/app/assets/javascripts/kojac_ember.js +463 -0
  12. data/app/controllers/kojac_controller.rb +70 -0
  13. data/app/serializers/default_kojac_serializer.rb +10 -0
  14. data/diagram.odg +0 -0
  15. data/kojac.gemspec +36 -0
  16. data/lib/kojac/app_serialize.rb +29 -0
  17. data/lib/kojac/kojac_rails.rb +432 -0
  18. data/lib/kojac/ring_strong_parameters.rb +195 -0
  19. data/lib/kojac/version.rb +3 -0
  20. data/lib/kojac.rb +8 -0
  21. data/lib/tasks/kojac_tasks.rake +4 -0
  22. data/notes.txt +48 -0
  23. data/spec/.DS_Store +0 -0
  24. data/spec/can_cache_spec.js +87 -0
  25. data/spec/can_factory_spec.js +144 -0
  26. data/spec/can_model_spec.js +127 -0
  27. data/spec/demo/README.rdoc +261 -0
  28. data/spec/demo/Rakefile +7 -0
  29. data/spec/demo/app/assets/javascripts/application.js +15 -0
  30. data/spec/demo/app/assets/stylesheets/application.css +13 -0
  31. data/spec/demo/app/controllers/application_controller.rb +3 -0
  32. data/spec/demo/app/helpers/application_helper.rb +2 -0
  33. data/spec/demo/app/mailers/.gitkeep +0 -0
  34. data/spec/demo/app/models/.gitkeep +0 -0
  35. data/spec/demo/app/views/layouts/application.html.erb +14 -0
  36. data/spec/demo/config/application.rb +65 -0
  37. data/spec/demo/config/boot.rb +10 -0
  38. data/spec/demo/config/database.yml +25 -0
  39. data/spec/demo/config/environment.rb +5 -0
  40. data/spec/demo/config/environments/development.rb +37 -0
  41. data/spec/demo/config/environments/production.rb +67 -0
  42. data/spec/demo/config/environments/test.rb +37 -0
  43. data/spec/demo/config/initializers/backtrace_silencers.rb +7 -0
  44. data/spec/demo/config/initializers/inflections.rb +15 -0
  45. data/spec/demo/config/initializers/mime_types.rb +5 -0
  46. data/spec/demo/config/initializers/secret_token.rb +7 -0
  47. data/spec/demo/config/initializers/session_store.rb +8 -0
  48. data/spec/demo/config/initializers/wrap_parameters.rb +14 -0
  49. data/spec/demo/config/locales/en.yml +5 -0
  50. data/spec/demo/config/routes.rb +58 -0
  51. data/spec/demo/config.ru +4 -0
  52. data/spec/demo/lib/assets/.gitkeep +0 -0
  53. data/spec/demo/log/.gitkeep +0 -0
  54. data/spec/demo/public/404.html +26 -0
  55. data/spec/demo/public/422.html +26 -0
  56. data/spec/demo/public/500.html +25 -0
  57. data/spec/demo/public/favicon.ico +0 -0
  58. data/spec/demo/script/rails +6 -0
  59. data/spec/ember_factory_spec.js +157 -0
  60. data/spec/ember_model_spec.js +179 -0
  61. data/spec/external/.DS_Store +0 -0
  62. data/spec/external/ember/.DS_Store +0 -0
  63. data/spec/external/ember/ember-1.0.0-rc.6.js +30970 -0
  64. data/spec/external/ember/handlebars-1.0.0-rc.4.js +2239 -0
  65. data/spec/external/jasmine/MIT.LICENSE +20 -0
  66. data/spec/external/jasmine/jasmine-html.js +616 -0
  67. data/spec/external/jasmine/jasmine.css +81 -0
  68. data/spec/external/jasmine/jasmine.js +2529 -0
  69. data/spec/external/jasmine.async.js +51 -0
  70. data/spec/external/jquery/jquery-1.7.2.js +9404 -0
  71. data/spec/external/jquery/jquery-1.7.2.min.js +4 -0
  72. data/spec/external/jquery/jquery-1.9.1.js +9597 -0
  73. data/spec/external/json2.js +480 -0
  74. data/spec/external/steal/steal-121115.js +2747 -0
  75. data/spec/external/steal/steal-3.2.3.js +2098 -0
  76. data/spec/external/steal/steal-3.2.3.min.js +27 -0
  77. data/spec/external/steal/steal.js +2466 -0
  78. data/spec/external/steal/steal.min.js +32 -0
  79. data/spec/external/steal/stealconfig.js +19 -0
  80. data/spec/external/underscore.js +1223 -0
  81. data/spec/external/underscore_plus.js +261 -0
  82. data/spec/external.zip +0 -0
  83. data/spec/handler_stack_spec.js +143 -0
  84. data/spec/helpers/SpecHelper.js +10 -0
  85. data/spec/kojac_caching_spec.js +105 -0
  86. data/spec/kojac_mock_spec.js +230 -0
  87. data/spec/kojac_model_spec.js +126 -0
  88. data/spec/kojac_object_spec.js +171 -0
  89. data/spec/kojac_operations_spec.js +41 -0
  90. data/spec/mockjson/order_item.js +37 -0
  91. data/spec/mockjson/order_item__49.js +15 -0
  92. data/spec/mockjson/order_item__50.js +15 -0
  93. data/spec/mockjson/order_item__51.js +15 -0
  94. data/spec/mockjson/product.js +82 -0
  95. data/spec/mockjson/product__3.js +22 -0
  96. data/spec/model_ring_spec.rb +52 -0
  97. data/spec/operation_include_spec.js +77 -0
  98. data/spec/run.html +81 -0
  99. data/spec/spec.js +2 -0
  100. data/spec/support/jasmine.yml +86 -0
  101. metadata +380 -0
@@ -0,0 +1,261 @@
1
+ // underscore_plus.js
2
+ // (c) 2012 Gary McGhee, Buzzware Solutions
3
+ // https://github.com/buzzware/underscore_plus
4
+ // Underscore may be freely distributed under the MIT license.
5
+
6
+ (function() {
7
+
8
+ //BEGIN copied from underscore
9
+ var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
10
+ // Create quick reference variables for speed access to core prototypes.
11
+ var slice = ArrayProto.slice;
12
+ //END copied from underscore
13
+
14
+ _.stringify = function(aObject) {
15
+ if (_.isString(aObject))
16
+ return aObject;
17
+ if (aObject===null || aObject===undefined)
18
+ return '';
19
+ if (aObject.toString)
20
+ return aObject.toString();
21
+ return '';
22
+ };
23
+
24
+ //var MAX_DUMP_DEPTH = 10;
25
+ //
26
+ // function dumpObj(obj, name, indent, depth) {
27
+ // if (depth > MAX_DUMP_DEPTH) {
28
+ // return indent + name + ": <Maximum Depth Reached>\n";
29
+ // }
30
+ // if (typeof obj == "object") {
31
+ // var child = null;
32
+ // var output = indent + name + "\n";
33
+ // indent += "\t";
34
+ // for (var item in obj)
35
+ // {
36
+ // try {
37
+ // child = obj[item];
38
+ // } catch (e) {
39
+ // child = "<Unable to Evaluate>";
40
+ // }
41
+ // if (typeof child == "object") {
42
+ // output += dumpObj(child, item, indent, depth + 1);
43
+ // } else {
44
+ // output += indent + item + ": " + child + "\n";
45
+ // }
46
+ // }
47
+ // return output;
48
+ // } else {
49
+ // return obj;
50
+ // }
51
+ // }
52
+
53
+ _.concat = function(aArray,aAnotherArray) {
54
+ var result = [];
55
+ result.push.apply(result, aArray);
56
+ result.push.apply(result, aAnotherArray);
57
+ return result;
58
+ };
59
+
60
+ _.nameValueString = function(aObject) {
61
+ return _.map(_.keys(aObject),function(k) { return k+'="'+_.stringify(aObject[k])+'"'}).join(' ');
62
+ };
63
+
64
+ _.classEnsure = function(aOrig,aNew) {
65
+ if (!aOrig)
66
+ return aNew;
67
+ if (!aNew)
68
+ return aOrig;
69
+ return _.union(aOrig.split(' '),aNew.split(' '));
70
+ };
71
+
72
+ _.getPath = function(aObject,aPath,aDefault) {
73
+ if ((typeof aObject)=='string') { // allow aObject to be left out and assume this
74
+ if (arguments.length==1) {
75
+ aPath = aObject;
76
+ aObject = window;
77
+ } else if (arguments.length==2) {
78
+ aDefault = aPath;
79
+ aPath = aObject;
80
+ aObject = window;
81
+ }
82
+ }
83
+ var nodes = aPath.split('.');
84
+ var curr = aObject;
85
+ for (var i=0;i<nodes.length;i++) {
86
+ var name = nodes[i];
87
+ if ((curr===undefined)||(curr===null))
88
+ return aDefault;
89
+ if ((name in curr) || curr[name]) {
90
+ var val = curr[name];
91
+ if ((typeof val)=='function')
92
+ curr = val.call(curr);
93
+ else
94
+ curr = val;
95
+ } else {
96
+ return aDefault; // name doesn't exist
97
+ }
98
+ }
99
+ return curr;
100
+ }
101
+
102
+ _.moveKeys = function(aDest,aSource,aKeys) {
103
+ if (!aSource)
104
+ return aDest;
105
+ if (!aKeys)
106
+ aKeys = _.keys(aSource);
107
+ for (var i=0;i<aKeys.length;i++) {
108
+ var k = aKeys[i];
109
+ if (!(k in aSource))
110
+ continue;
111
+ aDest[k] = aSource[k];
112
+ delete aSource[k];
113
+ }
114
+ return aDest;
115
+ };
116
+
117
+ _.removeKey = function(aObject,aKey) {
118
+ var result = aObject[aKey];
119
+ delete aObject[aKey];
120
+ return result;
121
+ };
122
+
123
+ // // find all dynamic objects in an array that have matching values for the contents of aAndCriteria
124
+ // public static function ObjectArrayFind(aArray:Array, aAndCriteria:Object):Array {
125
+ // return aArray.filter(
126
+ // function(item:*, index:int, array:Array):Boolean {
127
+ // // for all items in aAndCriteria, aItem has matching values
128
+ // for (var i:String in aAndCriteria) {
129
+ // if (aAndCriteria[i] != item[i])
130
+ // return false;
131
+ // }
132
+ // return true;
133
+ // }
134
+ // );
135
+ // }
136
+ //
137
+ // // like ObjectArrayFind except only returns one object. Could be optimised to quit searching when one is found
138
+ // // adds listener and removes on first occurrence
139
+ // public static function ObjectArrayFindOne(aArray:Array, aAndCriteria:Object):Object {
140
+ // var results:Array = ObjectArrayFind(aArray, aAndCriteria);
141
+ // return results[0];
142
+ // }
143
+ //
144
+ // public static function ObjectArrayLookup(aArray:Array, aAndCriteria:Object, aProperty:String):Object {
145
+ // var results:Array = ObjectArrayFind(aArray, aAndCriteria);
146
+ // var item:Object = results[0];
147
+ // if (!item)
148
+ // return null;
149
+ // return item[aProperty];
150
+ // }
151
+
152
+ _.hasMatchingProperties = function(aObject,aCriteria) {
153
+ for (var p in aCriteria) {
154
+ if (!(p in aObject) || (aObject[p]!==aCriteria[p]))
155
+ return false;
156
+ }
157
+ return true;
158
+ };
159
+
160
+ // find one item matching object properties
161
+ _.findByCriteria = function(aArray,aCriteria) {
162
+ return _.find(aArray,function(obj){
163
+ return _.hasMatchingProperties(obj,aCriteria);
164
+ });
165
+ };
166
+
167
+ // find one item matching object properties
168
+ _.filterByCriteria = function(aArray,aCriteria) {
169
+ return _.filter(aArray,function(obj){
170
+ return _.hasMatchingProperties(obj,aCriteria);
171
+ });
172
+ };
173
+
174
+ _.isObjectStrict = function(aSomething) {
175
+ return Object.prototype.toString.call(aSomething)==='[object Object]';
176
+ }
177
+
178
+ // create an object using key,value arguments eg. createObject('a',2) returns {a: 2}
179
+ _.createObject = function() {
180
+ var result = {};
181
+ result[arguments[0]] = arguments[1];
182
+ return result;
183
+ }
184
+
185
+ _.endsWith = function(aString, aSuffix) {
186
+ var i = aString.lastIndexOf(aSuffix);
187
+ return (i>=0 && i===aString.length-aSuffix.length);
188
+ }
189
+
190
+ _.beginsWith = function(aString, aPrefix) {
191
+ var i = aString.indexOf(aPrefix);
192
+ return (i==0);
193
+ }
194
+
195
+ _.chop = function(aString, aSuffix) {
196
+ var i = aString.lastIndexOf(aSuffix);
197
+ return (i===aString.length-aSuffix.length) ? aString.substring(0,i) : aString;
198
+ }
199
+
200
+ _.bite = function(aString, aPrefix) {
201
+ var i = aString.indexOf(aPrefix);
202
+ return (i===0) ? aString.substring(aPrefix.length) : aString;
203
+ }
204
+
205
+ _.typeOf = function(aSomething) {
206
+ if (aSomething===undefined)
207
+ return 'undefined';
208
+ if (aSomething===null)
209
+ return 'null';
210
+
211
+ var result = Object.prototype.toString.call(aSomething);
212
+ result = _.bite(result,'[object ');
213
+ result = _.chop(result,']');
214
+ return result.toLowerCase();
215
+ }
216
+
217
+ /**
218
+ * Clone properties that are objects or arrays, otherwise if aSource and aDestination are different, properties will be copied
219
+ * @param aDestination
220
+ * @param aSource (optional, defaults to aSource)
221
+ * @return aDestination
222
+ */
223
+ _.cloneComplexValues = function (aDestination, aSource) {
224
+ if (!aSource)
225
+ aSource = aDestination;
226
+ for (var p in aSource) {
227
+ var t = _.typeOf(aSource[p]);
228
+ if (t==='array' || t==='object')
229
+ aDestination[p] = _.clone(aSource[p]);
230
+ else if (aDestination!==aSource)
231
+ aDestination[p] = aSource[p];
232
+ }
233
+ return aDestination;
234
+ }
235
+
236
+ // http://justtalkaboutweb.com/2008/01/06/javascript-object-extension/
237
+
238
+ _.originalClone = _.originalClone || _.clone;
239
+ // Create a copy (shallow or deep) of an object from https://github.com/cederberg/underscore/commits/feature-clone
240
+ _.clone = function(obj, deep) {
241
+ if (!deep)
242
+ return _.originalClone(obj);
243
+ if (!_.isObject(obj) || _.isFunction(obj)) return obj;
244
+ if (_.isDate(obj)) return new Date(obj.getTime());
245
+ if (_.isRegExp(obj)) return new RegExp(obj.source, obj.toString().replace(/.*\//, ""));
246
+ var isArr = (_.isArray(obj) || _.isArguments(obj));
247
+ if (deep) {
248
+ var func = function (memo, value, key) {
249
+ if (isArr)
250
+ memo.push(_.clone(value, true));
251
+ else
252
+ memo[key] = _.clone(value, true);
253
+ return memo;
254
+ };
255
+ return _.reduce(obj, func, isArr ? [] : {});
256
+ } else {
257
+ return isArr ? slice.call(obj) : _.extend({}, obj);
258
+ }
259
+ };
260
+
261
+ }).call(this);
data/spec/external.zip ADDED
Binary file
@@ -0,0 +1,143 @@
1
+ describe("HandlerStack", function() {
2
+
3
+ it("simple add", function() {
4
+ var hs = new HandlerStack();
5
+ var context = {text: 'A'};
6
+
7
+ hs.add(function(aContext) {
8
+ context.text += 'B';
9
+ });
10
+ hs.add(function(aContext) {
11
+ context.text += 'C';
12
+ });
13
+ runs(function() {
14
+ hs.run(context);
15
+ });
16
+ waitsFor(function() { return context.isResolved(); }, "request done", 3000);
17
+ runs(function() {
18
+ expect(context.text).toBe('ABC');
19
+ });
20
+ });
21
+
22
+ it("add, push, then and done", function() {
23
+ var hs = new HandlerStack();
24
+ var context = {text: 'A'};
25
+
26
+ hs.add(function(aContext) {
27
+ context.text += 'B';
28
+ });
29
+ hs.add(function(aContext) {
30
+ context.text += 'C';
31
+ });
32
+ hs.push(function(aContext) {
33
+ context.text += 'X';
34
+ });
35
+ runs(function() {
36
+ hs.run(context);
37
+ context.then(function(aContext){
38
+ context.text += 'W';
39
+ });
40
+ context.done(function(aContext){
41
+ context.text += 'Z';
42
+ });
43
+ });
44
+ waitsFor(function() { return context.isResolved(); }, "request done", 3000);
45
+ runs(function() {
46
+ expect(context.text).toBe('AXBCWZ');
47
+ });
48
+ });
49
+
50
+ it("error handling - stop processing handlers and set context.error and context.isRejected and call fail handler", function() {
51
+ var hs = new HandlerStack();
52
+ var context = {text: 'A'};
53
+
54
+ hs.add(function(aContext) {
55
+ context.text += 'B';
56
+ });
57
+ hs.add(function(aContext) {
58
+ throw new Error();
59
+ });
60
+ hs.add(function(aContext) {
61
+ context.text += 'X';
62
+ });
63
+ hs.run(context);
64
+ context.then(function(aContext){
65
+ context.text += 'W';
66
+ });
67
+ context.done(function(aContext){
68
+ context.text += 'Z';
69
+ });
70
+ context.fail(function(aContext){
71
+ context.text += 'F';
72
+ });
73
+ waitsFor(function() {
74
+ return context.isRejected();
75
+ }, "rejected", 3000);
76
+ runs(function() {
77
+ expect(context.text).toBe('ABF');
78
+ expect(context.error).toBeDefined();
79
+ expect(typeof(context.error)).toBe('object');
80
+ });
81
+ });
82
+
83
+ it("reset and recall", function() {
84
+ var hs = new HandlerStack();
85
+ var context = {text: 'A'};
86
+
87
+ hs.add(function(aContext) {
88
+ context.text += 'B';
89
+ });
90
+ runs(function() {
91
+ hs.run(context);
92
+ context.then(function(aContext){
93
+ context.text += 'W';
94
+ });
95
+ context.done(function(aContext){
96
+ context.text += 'Z';
97
+ });
98
+ });
99
+ waitsFor(function() { return context.isResolved(); }, "resolved", 3000);
100
+ runs(function() {
101
+ expect(context.text).toBe('ABWZ');
102
+ expect(context.error).toBeUndefined();
103
+ hs.reset();
104
+ });
105
+
106
+ runs(function() {
107
+ context = {text: 'G'};
108
+ hs.run(context);
109
+ context.then(function(aContext){
110
+ context.text += 'W';
111
+ });
112
+ context.done(function(aContext){
113
+ context.text += 'Z';
114
+ });
115
+ });
116
+ waitsFor(function() { return context.isResolved(); }, "resolved", 3000);
117
+ runs(function() {
118
+ expect(context.text).toBe('GBWZ');
119
+ expect(context.error).toBeUndefined();
120
+ });
121
+
122
+ });
123
+
124
+ it("handler on an object", function() {
125
+ var hs = new HandlerStack();
126
+ var context = {text: 'A'};
127
+ var TestClass = function() {
128
+ this.text = 'B';
129
+ this.go = function(aContext) {
130
+ aContext.text += this.text;
131
+ };
132
+ };
133
+ var testClass = new TestClass();
134
+ hs.add(testClass.go,null,testClass); // note: using ability to specify this as third parameter
135
+ runs(function() {
136
+ hs.run(context);
137
+ });
138
+ waitsFor(function() { return context.isResolved(); }, "resolved", 3000);
139
+ runs(function() {
140
+ expect(context.text).toBe('AB');
141
+ });
142
+ });
143
+ });
@@ -0,0 +1,10 @@
1
+ //beforeEach(function() {
2
+ // this.addMatchers({
3
+ // toBePlaying: function(expectedSong) {
4
+ // var player = this.actual;
5
+ // return player.currentlyPlayingSong === expectedSong &&
6
+ // player.isPlaying;
7
+ // }
8
+ // });
9
+ //});
10
+
@@ -0,0 +1,105 @@
1
+ describe("Kojac Caching", function() {
2
+
3
+ beforeEach(function () {
4
+ this.cache = new Kojac.Object();
5
+ this.kojac = new Kojac.Core({
6
+ cache: this.cache,
7
+ remoteProvider: new Kojac.RemoteProvider({useMockFileValues: true,mockFilePath: 'mockjson/'})
8
+ });
9
+ });
10
+
11
+ it("should return extra keys from a cacheRead that were returned from the server",function(){
12
+ var products_records = { // this is the normal data to return when requesting 'products'
13
+ products: [1,2,3],
14
+ products__1: {
15
+ id: 1,
16
+ name: "Product One"
17
+ },
18
+ products__2: {
19
+ id: 2,
20
+ name: "Product Two"
21
+ },
22
+ products__3: {
23
+ id: 3,
24
+ name: "Product Three"
25
+ }
26
+ };
27
+ var products_server_response = _.clone(products_records); // the contents of this var will be returned by the mock server
28
+ this.kojac.remoteProvider.mockReadOperationHandler = function(aOp) { // this function acts as the server
29
+ switch (aOp.key) {
30
+ case 'products':
31
+ aOp.result_key = 'products';
32
+ aOp.results = _.extend(aOp.results,products_server_response);
33
+ break;
34
+ }
35
+ };
36
+ var readReq = this.kojac.readRequest('products');
37
+ waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
38
+ runs(function() {
39
+ expect(readReq.results).toEqual(products_records); // should equal normal response
40
+ products_server_response = {}; // kill server response - non-cache reads should return empty now
41
+ readReq = this.kojac.readRequest('products',{cacheResults: false}); // read from server to check this, and don't store result in cache
42
+ });
43
+ waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
44
+ runs(function() {
45
+ expect(readReq.results).toEqual({}); // indeed, server now returns empty, but lets try cache
46
+ readReq = this.kojac.cacheReadRequest('products'); // read from cache
47
+ });
48
+ waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
49
+ runs(function() {
50
+ expect(readReq.results).toEqual(products_records); // should return original records - must be coming from cache not server
51
+ });
52
+ });
53
+
54
+ it("should return extra keys from a cacheRead that were returned from the server, using result_key",function(){
55
+ var products_records = { // this is the normal data to return when requesting 'products'
56
+ products: [1,2,3],
57
+ products__1: {
58
+ id: 1,
59
+ name: "Product One"
60
+ },
61
+ products__2: {
62
+ id: 2,
63
+ name: "Product Two"
64
+ },
65
+ products__3: {
66
+ id: 3,
67
+ name: "Product Three"
68
+ }
69
+ };
70
+ var products_server_response = _.clone(products_records); // the contents of this var will be returned by the mock server
71
+ this.kojac.remoteProvider.mockReadOperationHandler = function(aOp) { // this function acts as the server
72
+ switch (aOp.key) {
73
+ case 'products':
74
+ if (aOp.result_key!==aOp.key)
75
+ products_server_response[aOp.result_key] = _.removeKey(products_server_response,aOp.key);
76
+ aOp.results = _.extend(aOp.results,products_server_response);
77
+ break;
78
+ }
79
+ };
80
+ expect(_.keys(this.kojac.cache)).toEqual([]);
81
+ var readReq = this.kojac.readRequest('products',{result_key: 'products_latest'});
82
+ waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
83
+ runs(function() {
84
+ var expected = _.clone(products_records);
85
+ expected.products_latest = _.removeKey(expected,'products');
86
+ expect(readReq.results).toEqual(expected); // should equal normal response
87
+ expect(_.keys(this.kojac.cache).sort()).toEqual(['products__1','products__2','products__3','products_latest']);
88
+ products_server_response = {}; // kill server response - non-cache reads should return empty now
89
+ readReq = this.kojac.readRequest('products',{cacheResults: false, result_key: 'products_latest'}); // read from server to check this, and don't store result in cache
90
+ });
91
+ waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
92
+ runs(function() {
93
+ expect(readReq.results).toEqual({}); // indeed, server now returns empty, but lets try cache
94
+ readReq = this.kojac.cacheReadRequest('products',{result_key: 'products_latest'}); // read from cache
95
+ });
96
+ waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
97
+ runs(function() {
98
+ var expected = _.clone(products_records);
99
+ expected.products_latest = _.removeKey(expected,'products');
100
+ expect(readReq.results).toEqual(expected); // should return original records - must be coming from cache not server
101
+ });
102
+ });
103
+
104
+ });
105
+