]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | describe("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 |