Upgrade to ExtJS 3.2.0 - Released 03/30/2010
[extjs.git] / test / unit / data / Store.js
1 /*!
2  * Ext JS Library 3.2.0
3  * Copyright(c) 2006-2010 Ext JS, Inc.
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * Tests Ext.data.Store functionality
9  * @author Ed Spencer
10  */
11 (function() {
12     var suite  = Ext.test.session.getSuite('Ext.data.Store'),
13         assert = Y.Assert;
14
15     //a shared setup function used by several of the suites
16     var defaultSetup = function() {
17         this.store = new Ext.data.Store({
18             proxy : new Ext.data.MemoryProxy({}),
19             reader: new Ext.data.ArrayReader({}, [
20                 {name: 'name',      type: 'string'},
21                 {name: 'email',     type: 'string'},
22                 {name: 'greatness', type: 'int'},
23                 {name: 'group',     type: 'string'},
24                 {name: 'old',       type: 'boolean'}
25             ]),
26             storeId: 'myStore',
27             remoteSort: false
28         });
29
30         this.store.loadData([
31             ['Ed Spencer',   'ed@extjs.com',    100, 'code',  false],
32             ['Abe Elias',    'abe@extjs.com',   70,  'admin', false],
33             ['Aaron Conran', 'aaron@extjs.com', 5,   'admin', true],
34             ['Tommy Maintz', 'tommy@extjs.com', -15, 'code',  true]
35         ]);
36     };
37
38     suite.add(new Y.Test.Case({
39         name: 'local single sorting',
40
41         setUp: defaultSetup,
42
43         testSetDefaultSort: function() {
44             this.store.setDefaultSort('name', 'DESC');
45
46             var store    = this.store,
47                 sortInfo = store.sortInfo;
48
49             assert.areEqual('name', sortInfo.field);
50             assert.areEqual('DESC', sortInfo.direction);
51             assert.areEqual('DESC', store.sortToggle['name']);
52         },
53
54         testSetDefaultSortDefaultToASC: function() {
55             this.store.setDefaultSort('email');
56
57             var store    = this.store,
58                 sortInfo = store.sortInfo;
59
60             assert.areEqual('email', sortInfo.field);
61             assert.areEqual('ASC', sortInfo['direction']);
62             assert.areEqual('ASC', store.sortToggle['email']);
63         },
64
65         testSortByField: function() {
66             var store = this.store;
67
68             store.sort('name', 'ASC');
69             assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
70             assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
71             assert.areEqual('Ed Spencer',   store.getAt(2).get('name'));
72             assert.areEqual('Tommy Maintz', store.getAt(3).get('name'));
73         },
74
75         testToggling: function() {
76             var store = this.store;
77
78             store.sort('name', 'ASC');
79
80             //second call to sort toggles the direction
81             store.sort('name');
82
83             assert.areEqual('Aaron Conran', store.getAt(3).get('name'));
84             assert.areEqual('Abe Elias',    store.getAt(2).get('name'));
85             assert.areEqual('Ed Spencer',   store.getAt(1).get('name'));
86             assert.areEqual('Tommy Maintz', store.getAt(0).get('name'));
87         },
88
89         testSetsHasMultiSort: function() {
90             this.store.sort('name', 'ASC');
91
92             assert.isFalse(this.store.hasMultiSort);
93         },
94
95         testEventFired: function() {
96             var executed = false,
97                 store    = this.store;
98
99             store.on('datachanged', function() {
100                 executed = true;
101             }, this);
102
103             store.sort('name');
104             assert.isTrue(executed);
105         },
106
107         testSavesSortInfo: function() {
108             var store = this.store;
109
110             store.sort('name', 'DESC');
111
112             assert.areEqual('name', store.sortInfo.field);
113             assert.areEqual('DESC', store.sortInfo.direction);
114         },
115
116         //if we tell store to sort on a non-existent field it should return false and do nothing
117         testInvalidFieldIgnored: function() {
118             var store = this.store;
119
120             //first we'll sort by name to give some reference sorting
121             store.sort('name', 'ASC');
122
123             assert.isFalse(store.sort('someUnknownField'));
124
125             //make sure the original sorting was preserved
126             assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
127             assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
128             assert.areEqual('Ed Spencer',   store.getAt(2).get('name'));
129             assert.areEqual('Tommy Maintz', store.getAt(3).get('name'));
130         }
131     }));
132
133     suite.add(new Y.Test.Case({
134         name: 'local multiple sorting',
135
136         setUp: function() {
137             defaultSetup.call(this);
138
139             this.sorters = [
140                 {
141                     field    : 'group',
142                     direction: 'ASC'
143                 },
144                 {
145                     field    : 'old',
146                     direction: 'DESC'
147                 }
148             ];
149         },
150
151         testSetsHasMultiSort: function() {
152             this.store.sort(this.sorters);
153
154             assert.isTrue(this.store.hasMultiSort);
155         },
156
157         testMultipleSorters: function() {
158             var store   = this.store,
159                 sorters = this.sorters;
160
161             store.sort(sorters);
162
163             assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
164             assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
165             assert.areEqual('Tommy Maintz', store.getAt(2).get('name'));
166             assert.areEqual('Ed Spencer',   store.getAt(3).get('name'));
167         }
168
169         // testMultipleSorterToggling: function() {
170         //     var store   = this.store,
171         //         sorters = this.sorters;
172         //
173         //     //first we'll sort to give some reference sorting
174         //     store.sort(sorters, "ASC");
175         //
176         //     //second call to sort toggles direction
177         //     store.sort(sorters);
178         //
179         //     assert.areEqual('Aaron Conran', store.getAt(3).get('name'));
180         //     assert.areEqual('Abe Elias',    store.getAt(2).get('name'));
181         //     assert.areEqual('Tommy Maintz', store.getAt(1).get('name'));
182         //     assert.areEqual('Ed Spencer',   store.getAt(0).get('name'));
183         // }
184     }));
185
186     suite.add(new Y.Test.Case({
187         name: 'single filtering',
188
189         setUp: defaultSetup,
190
191         testFilterByField: function() {
192             var store = this.store;
193
194             store.filter('group', 'code');
195             assert.areEqual(2, store.getCount());
196         },
197
198         testFilterByFieldAnyMatch: function() {
199             var store = this.store;
200
201             store.filter('email', 'extjs', true);
202             assert.areEqual(4, store.getCount());
203         },
204
205         testFilterByFieldCaseSensitive: function() {
206             var store = this.store;
207
208             store.filter('group', 'Code', false, true);
209             assert.areEqual(0, store.getCount());
210         },
211
212         testFilterByFieldExactMatch: function() {
213             var store = this.store;
214
215             store.filter('email', 'aaron', false, false, true);
216             assert.areEqual(0, store.getCount());
217         },
218
219         testClearFilter: function() {
220             var store    = this.store,
221                 executed = false;
222
223             store.on('datachanged', function() {
224                 executed = true;
225             }, this);
226
227             store.filter('group', 'code');
228             assert.areEqual(2, store.getCount());
229
230             store.clearFilter();
231             assert.areEqual(4, store.getCount());
232
233             assert.isTrue(executed);
234         },
235
236         testSuppressClearFilterEvent: function() {
237             var store    = this.store,
238                 executed = false;
239
240             store.filter('group', 'email');
241             store.clearFilter(true);
242
243             store.on('datachanged', function() {
244                 executed = true;
245             }, this);
246             assert.isFalse(executed);
247         },
248
249         testIsFiltered: function() {
250             var store = this.store;
251
252             assert.isFalse(store.isFiltered());
253             store.filter('group', 'code');
254             assert.isTrue(store.isFiltered());
255         },
256
257         testFilterByFunction: function() {
258             var store = this.store,
259                 execScope,
260                 executed;
261
262             store.on('datachanged', function() {
263                 executed = true;
264             }, this);
265
266             var filterFn = function(item) {
267                 execScope = this;
268
269                 return item.get('greatness') > 50;
270             };
271
272             store.filterBy(filterFn, this);
273             assert.areEqual(this, execScope);
274             assert.areEqual(2, store.getCount());
275             assert.isTrue(executed);
276         }
277     }));
278
279     suite.add(new Y.Test.Case({
280         name : 'filtering more than once',
281         setUp: defaultSetup,
282
283         testFirstFilterIsCleared: function() {
284             var store = this.store;
285
286             store.filter('group', 'code');
287             assert.areEqual(2, store.getCount());
288
289             store.filter('old', false);
290
291             //if filter had not been reset first, count would be 1
292             assert.areEqual(2, store.getCount());
293         }
294     }));
295
296     suite.add(new Y.Test.Case({
297         name : 'multiple filters',
298         setUp: function() {
299             defaultSetup.call(this);
300
301             this.filters = [
302                 {
303                     property: 'group',
304                     value   : 'code'
305                 },
306                 {
307                     property: 'old',
308                     value   : true
309                 }
310             ];
311         },
312
313         testMultipleBasicFilters: function() {
314             this.store.filter(this.filters);
315
316             //applying the filter set above shoule yield one result
317             assert.areEqual(1, this.store.getCount());
318             assert.areEqual('Tommy Maintz', this.store.data.first().get('name'));
319         },
320
321         testMultiFiltersFiresDataChanged: function() {
322             var executed = false;
323
324             this.store.on('datachanged', function() {
325                 executed = true;
326             }, this);
327
328             this.store.filter(this.filters);
329
330             assert.isTrue(executed);
331         },
332
333         //tests that the anyMatch and caseSensitive defaults are correctly applied
334         testMultiFilterDefaults: function() {
335             //PENDING
336         },
337
338         //tests a single custom filter
339         testCustomFilter: function() {
340             var execScope;
341
342             //tests that the passed filter function is called
343             //tests that the filter is called in the right scope
344             this.store.filter({
345                 fn: function(record) {
346                     execScope = this;
347                     return record.get('group') == 'admin' && record.get('old') === true;
348                 },
349                 scope: this
350             });
351
352             assert.areEqual(this, execScope);
353             assert.areEqual(1, this.store.getCount());
354             assert.areEqual('Aaron Conran', this.store.data.first().get('name'));
355         },
356
357         //tests multiple filters where we pass in custom matcher functions
358         testMultiCustomFilters: function() {
359             this.store.filter([
360                 {
361                     fn: function(record) {
362                         return record.get('group') == 'admin';
363                     }
364                 },
365                 {
366                     fn: function(record) {
367                         return record.get('old') === false;
368                     }
369                 }
370             ]);
371
372             assert.areEqual(1, this.store.getCount());
373             assert.areEqual('Abe Elias', this.store.data.first().get('name'));
374         },
375
376         testBasicAndCustomFilters: function() {
377             //should return a single result - Ed Spencer
378             this.store.filter([
379                 {
380                     fn: function(record) {
381                         return record.get('old') === false;
382                     }
383                 },
384                 {
385                     property: 'group',
386                     value   : 'code'
387                 }
388             ]);
389
390             assert.areEqual(1, this.store.getCount());
391             assert.areEqual('Ed Spencer', this.store.data.first().get('name'));
392         },
393
394         testClearMultipleFilters: function() {
395             this.store.filter(this.filters);
396             assert.areEqual(1, this.store.getCount());
397
398             //make sure that clearing multiple filters is still correct
399             this.store.clearFilter();
400             assert.areEqual(4, this.store.getCount());
401         }
402     }));
403
404     suite.add(new Y.Test.Case({
405         name: 'inserting and removing',
406
407         testInsert: function() {
408             //PENDING
409         },
410
411         testInsertFiresAddEvent: function() {
412             //PENDING
413         },
414
415         testRemove: function() {
416             //PENDING
417         },
418
419         testRemoveAll: function() {
420             //PENDING
421         },
422
423         testRemoveAt: function() {
424             //PENDING
425         }
426     }));
427
428     suite.add(new Y.Test.Case({
429         name: 'destroying',
430
431         setUp: defaultSetup,
432
433         //we hijack Ext.StoreMgr.unregister temporarily and then set it back in this test case
434         testUnregistersFromStore: function() {
435             var executed   = false,
436                 arg        = undefined,
437                 unregister = Ext.StoreMgr.unregister;
438
439             Ext.StoreMgr.unregister = function(store) {
440                 executed = true;
441                 arg = store;
442             };
443
444             this.store.destroy();
445
446             assert.isTrue(executed);
447             assert.areEqual(this.store, arg);
448
449             Ext.StoreMgr.unregister = unregister;
450         },
451
452         testClearsData: function() {
453             var executed = false;
454             this.store.clearData = function() {
455                 executed = true;
456             };
457
458             this.store.destroy();
459             assert.isTrue(executed);
460         },
461
462         testDestroysProxy: function() {
463             var executed = false,
464                 arg      = undefined,
465                 proxy    = this.store.proxy,
466                 destroy  = Ext.destroy;
467
468             Ext.destroy = function(store) {
469                 executed = true;
470                 arg = store;
471             };
472
473             this.store.destroy();
474
475             assert.isTrue(executed);
476             assert.areEqual(proxy, arg);
477
478             Ext.destroy = destroy;
479         },
480
481         testUnsetsReferences: function() {
482             this.store.destroy();
483
484             assert.isNull(this.store.reader);
485             assert.isNull(this.store.writer);
486             assert.isNull(this.store.data);
487         },
488
489         testIsDestroyed: function() {
490             assert.isFalse(this.store.isDestroyed);
491
492             this.store.destroy();
493
494             assert.isTrue(this.store.isDestroyed);
495         }
496     }));
497
498     suite.add(new Y.Test.Case({
499         name: 'counting and iterators',
500
501         setUp: defaultSetup,
502
503         testGetCount: function() {
504             assert.areEqual(4, this.store.getCount());
505         },
506
507         testGetTotalCount: function() {
508             //PENDING - need a fake remote data set test with paging
509         },
510
511         testEach: function() {
512             var count = 0,
513                 callScope;
514
515             this.store.each(function() {
516                 callScope = this;
517                 count ++;
518             }, this);
519
520             assert.areEqual(4, count);
521             assert.areEqual(this, callScope);
522         },
523
524         testSum: function() {
525             var sum = this.store.sum('greatness');
526
527             assert.areEqual(160, sum);
528         },
529
530         testSumWithStartAndEnd: function() {
531             var sum = this.store.sum('greatness', 1, 3);
532
533             assert.areEqual(60, sum);
534         },
535
536         //a normal collect test - check that we're pulling the right values out of the store
537         testCollect: function() {
538             var values = this.store.collect('name');
539
540             assert.areEqual(4, values.length);
541             assert.areNotEqual(-1, values.indexOf("Ed Spencer"));
542             assert.areNotEqual(-1, values.indexOf("Abe Elias"));
543             assert.areNotEqual(-1, values.indexOf("Aaron Conran"));
544             assert.areNotEqual(-1, values.indexOf("Tommy Maintz"));
545         },
546
547         //checks that all collected values are unique
548         testCollectIsUnique: function() {
549             var values = this.store.collect('group');
550
551             assert.areEqual(2, values.length);
552             assert.areNotEqual(-1, values.indexOf("code"));
553             assert.areNotEqual(-1, values.indexOf("admin"));
554         }
555     }));
556
557     suite.add(new Y.Test.Case({
558         name: 'committing',
559
560         testCommitChanges: function() {
561             //PENDING
562         },
563
564         testRejectChanges: function() {
565             //PENDING
566         },
567
568         testAfterCommit: function() {
569             //PENDING
570         },
571
572         testAfterReject: function() {
573             //PENDING
574         }
575     }));
576
577     suite.add(new Y.Test.Case({
578         name: 'modified',
579
580         testGetModifiedRecords: function() {
581             //PENDING
582         }
583     }));
584
585     suite.add(new Y.Test.Case({
586         name: 'loading'
587     }));
588 })();