]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/test/specs/data/BufferedStore.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / test / specs / data / BufferedStore.js
CommitLineData
6527f429
DM
1describe("Ext.data.BufferedStore", function() {\r
2 var bufferedStore, captured,\r
3 synchronousLoad = true,\r
4 bufferedStoreLoad = Ext.data.BufferedStore.prototype.load,\r
5 loadStore;\r
6\r
7 function getData(start, limit) {\r
8 var end = start + limit,\r
9 recs = [],\r
10 i;\r
11\r
12 for (i = start; i < end; ++i) {\r
13 recs.push({\r
14 id: i + 1,\r
15 threadid: i + 1,\r
16 title: 'Title' + (i + 1)\r
17 });\r
18 }\r
19 return recs;\r
20 }\r
21\r
22 function satisfyRequests(total) {\r
23 var requests = Ext.Ajax.mockGetAllRequests(),\r
24 empty = total === 0,\r
25 request, params, data;\r
26\r
27 while (requests.length) {\r
28 request = requests[0];\r
29\r
30 captured.push(request.options.params);\r
31\r
32 params = request.options.params;\r
33 data = getData(empty ? 0 : params.start, empty ? 0 : params.limit);\r
34\r
35 Ext.Ajax.mockComplete({\r
36 status: 200,\r
37 responseText: Ext.encode({\r
38 total: (total || empty) ? total : 5000,\r
39 data: data\r
40 })\r
41 });\r
42\r
43 requests = Ext.Ajax.mockGetAllRequests();\r
44 }\r
45 }\r
46\r
47 function createStore(cfg) {\r
48 bufferedStore = new Ext.data.BufferedStore(Ext.apply({\r
49 model: 'spec.ForumThread',\r
50 pageSize: 100,\r
51 proxy: {\r
52 type: 'ajax',\r
53 url: 'fakeUrl',\r
54 reader: {\r
55 type: 'json',\r
56 rootProperty: 'data'\r
57 }\r
58 }\r
59 }, cfg));\r
60 }\r
61\r
62 beforeEach(function() {\r
63 // Override so that we can control asynchronous loading\r
64 loadStore = Ext.data.BufferedStore.prototype.load = function() {\r
65 bufferedStoreLoad.apply(this, arguments);\r
66 if (synchronousLoad) {\r
67 this.flushLoad.apply(this, arguments);\r
68 }\r
69 return this;\r
70 },\r
71\r
72 Ext.define('spec.ForumThread', {\r
73 extend: 'Ext.data.Model',\r
74 fields: [\r
75 'title', 'forumtitle', 'forumid', 'username', {\r
76 name: 'replycount',\r
77 type: 'int'\r
78 }, {\r
79 name: 'lastpost',\r
80 mapping: 'lastpost',\r
81 type: 'date',\r
82 dateFormat: 'timestamp'\r
83 },\r
84 'lastposter', 'excerpt', 'threadid'\r
85 ],\r
86 idProperty: 'threadid'\r
87 });\r
88\r
89 MockAjaxManager.addMethods();\r
90 captured = [];\r
91 });\r
92 \r
93 afterEach(function(){\r
94 // Undo the overrides.\r
95 Ext.data.BufferedStore.prototype.load = bufferedStoreLoad;\r
96\r
97 MockAjaxManager.removeMethods();\r
98 bufferedStore.destroy();\r
99 captured = bufferedStore = null;\r
100 Ext.data.Model.schema.clear();\r
101 Ext.undefine('spec.ForumThread');\r
102 });\r
103\r
104 it("should be able to lookup a record by its internalId", function() {\r
105 createStore();\r
106 bufferedStore.loadPage(1);\r
107 satisfyRequests();\r
108\r
109 var rec0 = bufferedStore.getAt(0);\r
110\r
111 // Lookup by the string version of internalId because that's how we get from DOM to record: https://sencha.jira.com/browse/EXTJS-15388\r
112 expect(bufferedStore.getByInternalId(String(rec0.internalId))).toBe(rec0);\r
113 });\r
114\r
115 it("should return undefined when the internalId does not exist", function() {\r
116 createStore();\r
117 bufferedStore.loadPage(1);\r
118 satisfyRequests();\r
119\r
120 // Looking up nonexistent internalId should return undefined\r
121 expect(bufferedStore.getByInternalId('DefinitelyDoesntExist')).toBeUndefined();\r
122 });\r
123\r
124 it("should be able to start from any page", function() {\r
125 createStore();\r
126 bufferedStore.loadPage(10);\r
127\r
128 satisfyRequests();\r
129\r
130 expect(bufferedStore.currentPage).toBe(10);\r
131 var page10 = bufferedStore.getRange(900, 999);\r
132 expect(page10.length).toBe(100);\r
133\r
134 // Page 10 contains records 900 to 999.\r
135 expect(page10[0].get('title')).toBe('Title901');\r
136 expect(page10[99].get('title')).toBe('Title1000');\r
137 });\r
138\r
139 it("should be able to find records in a buffered store", function() {\r
140 createStore();\r
141 bufferedStore.load();\r
142\r
143 satisfyRequests();\r
144\r
145 expect(bufferedStore.findBy(function(rec) {\r
146 return rec.get('title') === 'Title10';\r
147 })).toBe(9);\r
148\r
149 expect(bufferedStore.findExact('title', 'Title10')).toBe(9);\r
150\r
151 expect(bufferedStore.find('title', 'title10')).toBe(9);\r
152 });\r
153\r
154 it("should load the store when filtered", function() {\r
155 var spy = jasmine.createSpy();\r
156\r
157 createStore({\r
158 listeners: {\r
159 load: spy\r
160 }\r
161 });\r
162\r
163 // Filter mutation shuold trigger a load\r
164 bufferedStore.filter('title', 'panel');\r
165 satisfyRequests();\r
166 expect(spy).toHaveBeenCalled();\r
167 });\r
168\r
169 describe("sorting", function() {\r
170 it("should clear the data when calling sort with parameters when remote sorting", function() {\r
171 createStore();\r
172 bufferedStore.load();\r
173\r
174 satisfyRequests();\r
175\r
176 bufferedStore.sort();\r
177 expect(bufferedStore.data.getCount()).toBe(0);\r
178 satisfyRequests();\r
179 expect(bufferedStore.data.getCount()).toBe(300);\r
180 });\r
181\r
182 it("should call the beforesort event", function() {\r
183 var spy = jasmine.createSpy();\r
184\r
185 createStore({\r
186 listeners: {\r
187 beforesort: spy\r
188 }\r
189 });\r
190\r
191 // Sorter mutation shuold trigger a load\r
192 bufferedStore.sort('title', 'ASC');\r
193 satisfyRequests();\r
194 expect(spy).toHaveBeenCalled();\r
195 });\r
196\r
197 it("should load the store when sorted", function() {\r
198 var spy = jasmine.createSpy();\r
199\r
200 createStore({\r
201 listeners: {\r
202 load: spy\r
203 }\r
204 });\r
205\r
206 // Sorter mutation shuold trigger a load\r
207 bufferedStore.sort('title', 'ASC');\r
208 satisfyRequests();\r
209 expect(spy).toHaveBeenCalled();\r
210 });\r
211\r
212 it("should update the sorters when sorting by an existing key", function() {\r
213 createStore({\r
214 sorters: [{\r
215 property: 'title'\r
216 }]\r
217 });\r
218\r
219 bufferedStore.sort('title', 'DESC');\r
220 var sorter = bufferedStore.getSorters().getAt(0);\r
221 expect(sorter.getProperty()).toBe('title');\r
222 expect(sorter.getDirection()).toBe('DESC');\r
223 });\r
224\r
225 it('should only make one network request', function () {\r
226 var spy = jasmine.createSpy();\r
227\r
228 createStore({\r
229 listeners: {\r
230 load: spy\r
231 }\r
232 });\r
233\r
234 bufferedStore.filter('username', 'germanicus');\r
235 satisfyRequests();\r
236\r
237 expect(spy.callCount).toBe(1);\r
238 });\r
239 });\r
240\r
241 // Test for https://sencha.jira.com/browse/EXTJSIV-10338\r
242 // purgePageCount ensured that the viewSize could never be satisfied\r
243 // by small pages because they would keep being pruned.\r
244 it("should load the requested range when the pageSize is small", function() {\r
245 var spy = jasmine.createSpy();\r
246 createStore({\r
247 pageSize: 5,\r
248 listeners: {\r
249 load: spy\r
250 }\r
251 });\r
252\r
253 bufferedStore.load();\r
254\r
255 satisfyRequests();\r
256 expect(spy).toHaveBeenCalled();\r
257 });\r
258\r
259 describe('load', function () {\r
260 function doTest(records, status, str) {\r
261 var success = status >= 500;\r
262\r
263 it("should pass the records loaded, the operation & success=" + success + " to the callback, " + str, function () {\r
264 var spy = jasmine.createSpy(),\r
265 args;\r
266\r
267 createStore();\r
268\r
269 bufferedStore.load({\r
270 // Called after first prefetch and first page has been added.\r
271 callback: spy\r
272 });\r
273\r
274 Ext.Ajax.mockComplete({\r
275 status: status,\r
276 responseText: Ext.encode({\r
277 total: records.length,\r
278 data: records\r
279 })\r
280 });\r
281\r
282 args = spy.mostRecentCall.args;\r
283\r
284 expect(Ext.isArray(args[0])).toBe(true);\r
285\r
286 if (args[0].length) {\r
287 expect(args[0][0].isModel).toBe(true);\r
288 } else {\r
289 expect(Ext.isArray(args)).toBe(true);\r
290 }\r
291\r
292 expect(args[1].getAction()).toBe('read');\r
293 expect(args[1].$className).toBe('Ext.data.operation.Read');\r
294\r
295 expect(args[2]).toBe(true);\r
296\r
297 });\r
298 }\r
299\r
300 doTest([{}], 200, 'loaded with records');\r
301 doTest([{}], 500, 'loaded with records');\r
302 doTest([], 200, 'no records');\r
303 doTest([], 500, 'no records');\r
304\r
305 describe("should assign dataset index numbers to the records in the Store dependent upon configured pageSize", function () {\r
306 it("should not exceed 100 records", function () {\r
307 createStore();\r
308\r
309 var spy = jasmine.createSpy();\r
310 bufferedStore.load({\r
311 // Called after first prefetch and first page has been added.\r
312 callback: spy\r
313 });\r
314\r
315 satisfyRequests();\r
316\r
317 expect(spy).toHaveBeenCalled();\r
318 expect(bufferedStore.indexOf(bufferedStore.getAt(0))).toBe(0);\r
319 expect(bufferedStore.indexOf(bufferedStore.getAt(99))).toBe(99);\r
320 expect(spy.mostRecentCall.args[0].length).toBe(100);\r
321 });\r
322\r
323 it("should not exceed 50 records", function () {\r
324 createStore({\r
325 pageSize: 50\r
326 });\r
327\r
328 var spy = jasmine.createSpy();\r
329 bufferedStore.load({\r
330 // Called after first prefetch and first page has been added.\r
331 callback: spy\r
332 });\r
333\r
334 satisfyRequests(50);\r
335 expect(spy).toHaveBeenCalled();\r
336\r
337 expect(bufferedStore.indexOf(bufferedStore.getAt(0))).toBe(0);\r
338 expect(bufferedStore.indexOf(bufferedStore.getAt(49))).toBe(49);\r
339 expect(spy.mostRecentCall.args[0].length).toBe(50);\r
340 });\r
341 });\r
342 });\r
343\r
344 describe("reload", function () {\r
345\r
346 describe("beforeload event", function() {\r
347 it("should not clear the total count or data if beforeload returns false", function() {\r
348 createStore();\r
349 bufferedStore.load();\r
350 satisfyRequests();\r
351\r
352 var spy = jasmine.createSpy().andReturn(false);\r
353 bufferedStore.on('beforeload', spy);\r
354 bufferedStore.reload();\r
355 expect(bufferedStore.getTotalCount()).toBe(5000);\r
356 expect(bufferedStore.getAt(0).id).toBe(1);\r
357 expect(bufferedStore.isLoading()).toBe(false);\r
358 });\r
359 });\r
360\r
361 it("should not increase the number of pages when reloading", function () {\r
362 var refreshed = 0,\r
363 count;\r
364\r
365 createStore();\r
366 bufferedStore.load();\r
367\r
368 satisfyRequests();\r
369\r
370 bufferedStore.on('refresh', function() {\r
371 refreshed++;\r
372 });\r
373\r
374 bufferedStore.reload();\r
375 satisfyRequests();\r
376 \r
377 expect(refreshed).toBe(1);\r
378 count = bufferedStore.getData().getCount();\r
379\r
380 bufferedStore.reload();\r
381 satisfyRequests();\r
382 \r
383 expect(bufferedStore.getData().getCount()).toBe(count);\r
384 });\r
385\r
386 it("should fire the load & refresh event when the store reloads with no data", function() {\r
387 var loadSpy = jasmine.createSpy(),\r
388 refreshSpy = jasmine.createSpy();\r
389\r
390 createStore();\r
391 bufferedStore.load();\r
392 satisfyRequests();\r
393\r
394 bufferedStore.on('load', loadSpy);\r
395 bufferedStore.on('refresh', refreshSpy);\r
396\r
397 bufferedStore.reload();\r
398 satisfyRequests(0);\r
399\r
400 expect(loadSpy.callCount).toBe(1);\r
401 expect(loadSpy.mostRecentCall.args[0]).toBe(bufferedStore);\r
402 expect(loadSpy.mostRecentCall.args[1]).toEqual([]);\r
403 expect(loadSpy.mostRecentCall.args[2]).toBe(true);\r
404\r
405 expect(refreshSpy.callCount).toBe(1);\r
406 expect(refreshSpy.mostRecentCall.args[0]).toBe(bufferedStore);\r
407 });\r
408\r
409 it("should not request larger than the previous total, preserveScrollOnReload: true", function() {\r
410 var total = 6679,\r
411 viewSize = 50;\r
412\r
413 createStore({\r
414 leadingBufferZone: 300,\r
415 pageSize: 100,\r
416 defaultViewSize: viewSize,\r
417 preserveScrollOnReload: true\r
418 });\r
419\r
420 bufferedStore.load();\r
421 satisfyRequests(total);\r
422\r
423 bufferedStore.getRange(total - 1 - viewSize, total - 1);\r
424 satisfyRequests(total);\r
425\r
426 captured.length = 0;\r
427\r
428 bufferedStore.reload();\r
429 expect(function() {\r
430 satisfyRequests(total);\r
431 }).not.toThrow();\r
432\r
433 // Reloaded the last requested range\r
434 expect(captured[captured.length - 1]).toEqual({\r
435 page: 67,\r
436 start: 6600,\r
437 limit: 100\r
438 });\r
439 });\r
440\r
441 it("should not request larger than the previous total, preserveScrollOnReload: false", function() {\r
442 var total = 6679,\r
443 viewSize = 50;\r
444\r
445 createStore({\r
446 leadingBufferZone: 300,\r
447 pageSize: 100,\r
448 defaultViewSize: viewSize\r
449 });\r
450\r
451 bufferedStore.load();\r
452 satisfyRequests(total);\r
453\r
454 bufferedStore.getRange(total - 1 - viewSize, total - 1);\r
455 satisfyRequests(total);\r
456\r
457 captured.length = 0;\r
458\r
459 bufferedStore.reload();\r
460 expect(function() {\r
461 satisfyRequests(total);\r
462 }).not.toThrow();\r
463\r
464 // Reloaded from start\r
465 expect(captured[captured.length - 1]).toEqual({\r
466 page: 3,\r
467 start: 200,\r
468 limit: 100\r
469 });\r
470 });\r
471 });\r
472\r
473 describe("pruning", function() {\r
474 it("should prune least recently used pages as new ones are added above the purgePageCount", function() {\r
475 var keys;\r
476\r
477 // Keep it simple\r
478 createStore({\r
479 pageSize: 10,\r
480 viewSize: 10,\r
481 leadingBufferZone: 0,\r
482 trailingBufferZone: 0,\r
483 purgePageCount: new Number(0)\r
484 });\r
485 bufferedStore.load();\r
486 satisfyRequests();\r
487\r
488\r
489 // The PageMap should contain page 1\r
490 keys = [];\r
491 bufferedStore.getData().forEach(function(rec){\r
492 keys.push(String(rec.internalId));\r
493 });\r
494 expect(keys.length).toBe(10);\r
495 expect(Ext.Object.getKeys(bufferedStore.getData().map)).toEqual(['1']);\r
496\r
497 // The indexMap must contain only the keys to the records that are now there.\r
498 expect(Ext.Object.getKeys(bufferedStore.getData().indexMap)).toEqual(keys);\r
499\r
500 // This should not evict page one because the cache size is TWICE the required zone\r
501 bufferedStore.loadPage(2);\r
502 satisfyRequests();\r
503\r
504 // The PageMap should contain pages 1 and 2\r
505 keys = [];\r
506 bufferedStore.getData().forEach(function(rec){\r
507 keys.push(String(rec.internalId));\r
508 });\r
509 expect(keys.length).toBe(20);\r
510 expect(Ext.Object.getKeys(bufferedStore.getData().map)).toEqual(['1', '2']);\r
511\r
512 // The indexMap must contain only the keys to the records that are now there.\r
513 expect(Ext.Object.getKeys(bufferedStore.getData().indexMap)).toEqual(keys);\r
514\r
515 // This should evict page one because there are no buffer zones, and a non-falsy purgePageCount of zero\r
516 bufferedStore.loadPage(3);\r
517 satisfyRequests();\r
518\r
519 // The PageMap should contain pages 2 and 3\r
520 keys = [];\r
521 bufferedStore.getData().forEach(function(rec){\r
522 keys.push(String(rec.internalId));\r
523 });\r
524 expect(keys.length).toBe(20);\r
525 expect(Ext.Object.getKeys(bufferedStore.getData().map)).toEqual(['2', '3']);\r
526\r
527 // The indexMap must contain only the keys to the records that are now there.\r
528 expect(Ext.Object.getKeys(bufferedStore.getData().indexMap)).toEqual(keys);\r
529 });\r
530 });\r
531});\r
532\r