]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | describe('Ext.grid.feature.GroupingSummary', function () {\r |
2 | var data, grid, store, groupingSummary, columns, params, selector,\r | |
3 | synchronousLoad = true,\r | |
4 | proxyStoreLoad = Ext.data.ProxyStore.prototype.load,\r | |
5 | loadStore;\r | |
6 | \r | |
7 | function createGrid(gridCfg, groupingSummaryCfg, columns, storeCfg) {\r | |
8 | data = [{\r | |
9 | student: 'Student 1',\r | |
10 | subject: 'Math',\r | |
11 | mark: 84,\r | |
12 | allowance: 15.50\r | |
13 | },{\r | |
14 | student: 'Student 1',\r | |
15 | subject: 'Science',\r | |
16 | mark: 72,\r | |
17 | allowance: 10.75\r | |
18 | },{\r | |
19 | student: 'Student 2',\r | |
20 | subject: 'Math',\r | |
21 | mark: 96,\r | |
22 | allowance: 100.75\r | |
23 | },{\r | |
24 | student: 'Student 2',\r | |
25 | subject: 'Science',\r | |
26 | mark: 68,\r | |
27 | allowance: 1.55\r | |
28 | }];\r | |
29 | \r | |
30 | Ext.define('spec.GroupingSummary', {\r | |
31 | extend: 'Ext.data.Model',\r | |
32 | fields: [\r | |
33 | 'student',\r | |
34 | 'subject',\r | |
35 | {\r | |
36 | name: 'mark',\r | |
37 | type: 'int'\r | |
38 | },\r | |
39 | {\r | |
40 | name: 'allowance',\r | |
41 | type: 'float'\r | |
42 | }\r | |
43 | ]\r | |
44 | });\r | |
45 | \r | |
46 | storeCfg = Ext.apply({\r | |
47 | model: 'spec.GroupingSummary',\r | |
48 | data: data,\r | |
49 | autoDestroy: true\r | |
50 | }, storeCfg);\r | |
51 | \r | |
52 | if (!storeCfg.grouper && !storeCfg.hasOwnProperty('groupField')) {\r | |
53 | storeCfg.groupField = 'subject';\r | |
54 | }\r | |
55 | \r | |
56 | store = new Ext.data.Store(storeCfg);\r | |
57 | \r | |
58 | groupingSummary = new Ext.grid.feature.GroupingSummary(Ext.apply({\r | |
59 | ftype: 'groupingsummary'\r | |
60 | }, groupingSummaryCfg));\r | |
61 | \r | |
62 | columns = columns || [{\r | |
63 | itemId: 'studentColumn',\r | |
64 | dataIndex: 'student',\r | |
65 | text: 'Name',\r | |
66 | summaryType: 'count',\r | |
67 | summaryRenderer: function (value, summaryData, field, metaData) {\r | |
68 | params = arguments;\r | |
69 | return Ext.String.format('{0} student{1}', value, value !== 1 ? 's' : '');\r | |
70 | }\r | |
71 | }, {\r | |
72 | itemId: 'markColumn',\r | |
73 | dataIndex: 'mark',\r | |
74 | text: 'Mark',\r | |
75 | summaryType: 'average'\r | |
76 | }, {\r | |
77 | itemId: 'noDataIndexColumn',\r | |
78 | summaryType: function (records, values) {\r | |
79 | var i = 0,\r | |
80 | length = records.length,\r | |
81 | total = 0,\r | |
82 | record;\r | |
83 | \r | |
84 | for (; i < length; ++i) {\r | |
85 | record = records[i];\r | |
86 | total += record.get('allowance');\r | |
87 | }\r | |
88 | return total;\r | |
89 | },\r | |
90 | summaryRenderer: function (value, summaryData, field, metaData) {\r | |
91 | return Ext.util.Format.usMoney(value || metaData.record.get('allowance'));\r | |
92 | },\r | |
93 | renderer: function(value, metaData, record, rowIdx, colIdx, store, view) {\r | |
94 | return Ext.util.Format.usMoney(record.get('allowance'));\r | |
95 | }\r | |
96 | }];\r | |
97 | \r | |
98 | grid = new Ext.grid.Panel(Ext.apply({\r | |
99 | store: store,\r | |
100 | columns: columns,\r | |
101 | width: 600,\r | |
102 | height: 300,\r | |
103 | features: groupingSummary,\r | |
104 | renderTo: Ext.getBody()\r | |
105 | }, gridCfg));\r | |
106 | selector = groupingSummary.summaryRowSelector;\r | |
107 | }\r | |
108 | \r | |
109 | function expectData(fields, expected) {\r | |
110 | var groupInfo = groupingSummary.getMetaGroup(store.getGroups().getAt(0)),\r | |
111 | record = groupInfo.aggregateRecord;\r | |
112 | \r | |
113 | expect(record.get(fields[0])).toBe(expected[0]);\r | |
114 | expect(record.get(fields[1])).toBe(expected[1]);\r | |
115 | }\r | |
116 | \r | |
117 | function expectSummaryRow(view) {\r | |
118 | var summaryRow = grid.view.body.down('.x-grid-row-summary', true);\r | |
119 | \r | |
120 | expect((summaryRow.textContent || summaryRow.innerText).replace(/\s/g, '')).toBe(view);\r | |
121 | }\r | |
122 | \r | |
123 | beforeEach(function() {\r | |
124 | // Override so that we can control asynchronous loading\r | |
125 | loadStore = Ext.data.ProxyStore.prototype.load = function() {\r | |
126 | proxyStoreLoad.apply(this, arguments);\r | |
127 | if (synchronousLoad) {\r | |
128 | this.flushLoad.apply(this, arguments);\r | |
129 | }\r | |
130 | return this;\r | |
131 | };\r | |
132 | });\r | |
133 | \r | |
134 | afterEach(function() {\r | |
135 | // Undo the overrides.\r | |
136 | Ext.data.ProxyStore.prototype.load = proxyStoreLoad;\r | |
137 | \r | |
138 | grid.destroy();\r | |
139 | grid = store = groupingSummary = columns = params = null;\r | |
140 | Ext.undefine('spec.GroupingSummary');\r | |
141 | Ext.data.Model.schema.clear();\r | |
142 | });\r | |
143 | \r | |
144 | describe('summaryRenderer', function () {\r | |
145 | it('should be passed the expected function parameters', function () {\r | |
146 | // Note that we're only capturing the values for the second group.\r | |
147 | createGrid();\r | |
148 | \r | |
149 | // Params should be:\r | |
150 | // value - The calculated value.\r | |
151 | // summaryData - Contains all raw summary values for the row.\r | |
152 | // field - The name of the field we are calculating\r | |
153 | // metaData - The collection of metadata about the current cell.\r | |
154 | expect(params.length).toBe(4);\r | |
155 | expect(params[0]).toBe(2);\r | |
156 | expect(params[1]).toEqual({\r | |
157 | studentColumn: 2,\r | |
158 | markColumn: 70,\r | |
159 | noDataIndexColumn: 12.3\r | |
160 | });\r | |
161 | expect(params[2]).toBe('student');\r | |
162 | expect(params[3].tdCls).toBeDefined();\r | |
163 | });\r | |
164 | \r | |
165 | it('should be able to read the data from the summary record when there is no column.dataIndex', function () {\r | |
166 | var node;\r | |
167 | \r | |
168 | createGrid();\r | |
169 | \r | |
170 | // The "Student 2" item is a wrapper which also encapsulates the summary row.\r | |
171 | // It will contain 2 rows: Student 2 and the summary.\r | |
172 | node = grid.view.all.item(1, true);\r | |
173 | \r | |
174 | expect((node.textContent || node.innerText).replace(/\r\n?|\n/g, '')).toBe('Student 296$100.752 students90$116.25');\r | |
175 | });\r | |
176 | \r | |
177 | it('should update when group records are removed', function () {\r | |
178 | var mathGroup;\r | |
179 | \r | |
180 | createGrid();\r | |
181 | mathGroup = groupingSummary.summaryData.Math;\r | |
182 | \r | |
183 | // Pre-removal.\r | |
184 | expect(mathGroup.markColumn).toBe(90);\r | |
185 | expect(mathGroup.noDataIndexColumn).toBe(116.25);\r | |
186 | expect(mathGroup.studentColumn).toBe(2);\r | |
187 | \r | |
188 | store.removeAt(1);\r | |
189 | \r | |
190 | // The summaryData record should be updated.\r | |
191 | expect(mathGroup.markColumn).toBe(84);\r | |
192 | expect(mathGroup.noDataIndexColumn).toBe(15.5);\r | |
193 | expect(mathGroup.studentColumn).toBe(1);\r | |
194 | });\r | |
195 | });\r | |
196 | \r | |
197 | describe("toggling the summary row", function() {\r | |
198 | function toggle(visible) {\r | |
199 | groupingSummary.toggleSummaryRow(visible);\r | |
200 | }\r | |
201 | \r | |
202 | it("should show the summary row by default", function() {\r | |
203 | createGrid();\r | |
204 | expect(grid.getView().getEl().select(selector).getCount()).toBe(2);\r | |
205 | });\r | |
206 | \r | |
207 | it("should not render the summary rows if configured with showSummaryRow: false", function() {\r | |
208 | createGrid(null, {\r | |
209 | showSummaryRow: false\r | |
210 | });\r | |
211 | expect(grid.getView().getEl().select(selector).getCount()).toBe(0);\r | |
212 | });\r | |
213 | \r | |
214 | it("should not show summary rows when toggling off", function() {\r | |
215 | createGrid();\r | |
216 | expect(grid.getView().getEl().select(selector).getCount()).toBe(2);\r | |
217 | toggle();\r | |
218 | expect(grid.getView().getEl().select(selector).getCount()).toBe(0);\r | |
219 | });\r | |
220 | \r | |
221 | it("should show summary rows when toggling on", function() {\r | |
222 | createGrid(null, {\r | |
223 | showSummaryRow: false\r | |
224 | });\r | |
225 | expect(grid.getView().getEl().select(selector).getCount()).toBe(0);\r | |
226 | toggle();\r | |
227 | expect(grid.getView().getEl().select(selector).getCount()).toBe(2);\r | |
228 | });\r | |
229 | \r | |
230 | it("should leave the summary visible when explicitly passing visible: true", function() {\r | |
231 | createGrid();\r | |
232 | toggle(true);\r | |
233 | expect(grid.getView().getEl().select(selector).getCount()).toBe(2);\r | |
234 | });\r | |
235 | \r | |
236 | it("should leave the summary off when explicitly passed visible: false", function() {\r | |
237 | createGrid();\r | |
238 | toggle();\r | |
239 | toggle(false);\r | |
240 | expect(grid.getView().getEl().select(selector).getCount()).toBe(0);\r | |
241 | });\r | |
242 | \r | |
243 | it("should update the summary row if the change happened while not visible", function() {\r | |
244 | createGrid();\r | |
245 | // Off\r | |
246 | toggle();\r | |
247 | store.first().set('mark', 0);\r | |
248 | toggle();\r | |
249 | \r | |
250 | var row = grid.getView().getEl().select(selector).first(),\r | |
251 | cell = row.down(grid.down('#markColumn').getCellSelector());\r | |
252 | \r | |
253 | \r | |
254 | var content = cell.down(grid.getView().innerSelector).dom.innerHTML;\r | |
255 | expect(content).toBe('48');\r | |
256 | });\r | |
257 | });\r | |
258 | \r | |
259 | describe('when the view is refreshed', function () {\r | |
260 | function expectIt(data) {\r | |
261 | it('should retain the summary feature row information in the feature cache', function () {\r | |
262 | // Get the cached information that the feature is retaining for the Math group.\r | |
263 | var groupInfo = groupingSummary.getMetaGroup(store.getGroups().getAt(0)),\r | |
264 | record = groupInfo.aggregateRecord;\r | |
265 | \r | |
266 | expect(record.get('student')).toBe(data.student);\r | |
267 | expect(record.get('mark')).toBe(data.mark);\r | |
268 | expect(record.get('noDataIndexColumn')).toBe(data.noDataIndexColumn);\r | |
269 | });\r | |
270 | \r | |
271 | it('should retain the summary feature row information in the view', function () {\r | |
272 | var summaryRow = grid.view.body.down('.x-grid-row-summary', true);\r | |
273 | \r | |
274 | expect((summaryRow.textContent || summaryRow.innerText).replace(/\s/g, '')).toBe(data.view);\r | |
275 | });\r | |
276 | }\r | |
277 | \r | |
278 | describe('when toggling the enabled/disabled state of the groups', function () {\r | |
279 | // Note that the bug only happens when toggling twice (first to disable, then to enable).\r | |
280 | // See EXTJS-16141.\r | |
281 | beforeEach(function () {\r | |
282 | createGrid();\r | |
283 | \r | |
284 | groupingSummary.disable();\r | |
285 | groupingSummary.enable();\r | |
286 | });\r | |
287 | \r | |
288 | expectIt({\r | |
289 | student: 2,\r | |
290 | mark: 90,\r | |
291 | noDataIndexColumn: 116.25,\r | |
292 | view: '2students90$116.25'\r | |
293 | });\r | |
294 | });\r | |
295 | \r | |
296 | describe('when filtering the store', function () {\r | |
297 | // See EXTJS-15267.\r | |
298 | beforeEach(function () {\r | |
299 | createGrid();\r | |
300 | \r | |
301 | grid.store.addFilter({property: 'mark', operator: 'eq', value: 84})\r | |
302 | });\r | |
303 | \r | |
304 | describe('adding a filter', function () {\r | |
305 | expectIt({\r | |
306 | student: 1,\r | |
307 | mark: 84,\r | |
308 | noDataIndexColumn: 15.50,\r | |
309 | view: '1student84$15.50'\r | |
310 | });\r | |
311 | });\r | |
312 | \r | |
313 | describe('clearing the filters', function () {\r | |
314 | beforeEach(function () {\r | |
315 | grid.store.clearFilter();\r | |
316 | });\r | |
317 | \r | |
318 | expectIt({\r | |
319 | student: 2,\r | |
320 | mark: 90,\r | |
321 | noDataIndexColumn: 116.25,\r | |
322 | view: '2students90$116.25'\r | |
323 | });\r | |
324 | });\r | |
325 | });\r | |
326 | });\r | |
327 | \r | |
328 | describe('reconfiguring', function () {\r | |
329 | beforeEach(function () {\r | |
330 | createGrid();\r | |
331 | });\r | |
332 | \r | |
333 | describe('new store', function () {\r | |
334 | it('should update the summary row', function () {\r | |
335 | store = new Ext.data.Store({\r | |
336 | model: 'spec.GroupingSummary',\r | |
337 | groupField: 'subject',\r | |
338 | data: [{\r | |
339 | student: 'Student 1',\r | |
340 | subject: 'Math',\r | |
341 | mark: 84,\r | |
342 | allowance: 15.50\r | |
343 | },{\r | |
344 | student: 'Student 2',\r | |
345 | subject: 'Science',\r | |
346 | mark: 68,\r | |
347 | allowance: 1.55\r | |
348 | }],\r | |
349 | autoDestroy: true\r | |
350 | });\r | |
351 | \r | |
352 | grid.reconfigure(store);\r | |
353 | \r | |
354 | expectData(\r | |
355 | ['mark', 'noDataIndexColumn'],\r | |
356 | [84, 15.50]\r | |
357 | );\r | |
358 | \r | |
359 | expectSummaryRow('1student84$15.50');\r | |
360 | });\r | |
361 | });\r | |
362 | \r | |
363 | describe('new columns', function () {\r | |
364 | it('should update the summary row', function () {\r | |
365 | grid.reconfigure(null, [{\r | |
366 | itemId: 'studentColumn',\r | |
367 | dataIndex: 'student',\r | |
368 | text: 'Name',\r | |
369 | summaryType: 'count',\r | |
370 | summaryRenderer: function (value, summaryData, field, metaData) {\r | |
371 | params = arguments;\r | |
372 | return Ext.String.format('{0} student{1}', value, value !== 1 ? 's' : '');\r | |
373 | }\r | |
374 | }, {\r | |
375 | itemId: 'allowance',\r | |
376 | dataIndex: 'allowance',\r | |
377 | text: 'Allowance',\r | |
378 | summaryType: 'average'\r | |
379 | }]);\r | |
380 | \r | |
381 | expectData(\r | |
382 | ['student', 'allowance'],\r | |
383 | [2, 58.125]\r | |
384 | );\r | |
385 | \r | |
386 | expectSummaryRow('2students58.125');\r | |
387 | });\r | |
388 | });\r | |
389 | });\r | |
390 | \r | |
391 | describe("loading the store", function() {\r | |
392 | beforeEach(function() {\r | |
393 | MockAjaxManager.addMethods();\r | |
394 | });\r | |
395 | \r | |
396 | afterEach(function() {\r | |
397 | MockAjaxManager.removeMethods();\r | |
398 | });\r | |
399 | \r | |
400 | it("should update the summary when loading remote data", function() {\r | |
401 | createGrid(null, null, null, {\r | |
402 | data: null,\r | |
403 | proxy: {\r | |
404 | type: 'ajax',\r | |
405 | url: 'Foo'\r | |
406 | }\r | |
407 | });\r | |
408 | store.load();\r | |
409 | Ext.Ajax.mockComplete({\r | |
410 | status: 200,\r | |
411 | responseText: Ext.encode(data)\r | |
412 | });\r | |
413 | \r | |
414 | var rows = grid.view.el.query(groupingSummary.summaryRowSelector);\r | |
415 | \r | |
416 | expect((rows[0].textContent || rows[0].innerText).replace(/\s/g, '')).toBe('2students90$116.25');\r | |
417 | expect((rows[1].textContent || rows[1].innerText).replace(/\s/g, '')).toBe('2students70$12.30');\r | |
418 | \r | |
419 | store.load();\r | |
420 | Ext.Ajax.mockComplete({\r | |
421 | status: 200,\r | |
422 | responseText: Ext.encode([{\r | |
423 | student: 'Student 1',\r | |
424 | subject: 'Math',\r | |
425 | mark: 77,\r | |
426 | allowance: 30\r | |
427 | }, {\r | |
428 | student: 'Student 2',\r | |
429 | subject: 'Science',\r | |
430 | mark: 20,\r | |
431 | allowance: 30.12\r | |
432 | }, {\r | |
433 | student: 'Student 3',\r | |
434 | subject: 'Science',\r | |
435 | mark: 30,\r | |
436 | allowance: 12\r | |
437 | }, {\r | |
438 | student: 'Student 4',\r | |
439 | subject: 'Science',\r | |
440 | mark: 40,\r | |
441 | allowance: 1\r | |
442 | }])\r | |
443 | });\r | |
444 | \r | |
445 | rows = grid.view.el.query(groupingSummary.summaryRowSelector);\r | |
446 | \r | |
447 | expect((rows[0].textContent || rows[0].innerText).replace(/\s/g, '')).toBe('1student77$30.00');\r | |
448 | expect((rows[1].textContent || rows[1].innerText).replace(/\s/g, '')).toBe('3students30$43.12');\r | |
449 | });\r | |
450 | \r | |
451 | it("should update the summary when loading local data", function() {\r | |
452 | createGrid();\r | |
453 | \r | |
454 | var rows = grid.view.el.query(groupingSummary.summaryRowSelector);\r | |
455 | \r | |
456 | expect((rows[0].textContent || rows[0].innerText).replace(/\s/g, '')).toBe('2students90$116.25');\r | |
457 | expect((rows[1].textContent || rows[1].innerText).replace(/\s/g, '')).toBe('2students70$12.30');\r | |
458 | \r | |
459 | store.loadData([{\r | |
460 | student: 'Student 1',\r | |
461 | subject: 'Math',\r | |
462 | mark: 77,\r | |
463 | allowance: 30\r | |
464 | }, {\r | |
465 | student: 'Student 2',\r | |
466 | subject: 'Science',\r | |
467 | mark: 20,\r | |
468 | allowance: 30.12\r | |
469 | }, {\r | |
470 | student: 'Student 3',\r | |
471 | subject: 'Science',\r | |
472 | mark: 30,\r | |
473 | allowance: 12\r | |
474 | }, {\r | |
475 | student: 'Student 4',\r | |
476 | subject: 'Science',\r | |
477 | mark: 40,\r | |
478 | allowance: 1\r | |
479 | }]);\r | |
480 | \r | |
481 | rows = grid.view.el.query(groupingSummary.summaryRowSelector);\r | |
482 | \r | |
483 | expect((rows[0].textContent || rows[0].innerText).replace(/\s/g, '')).toBe('1student77$30.00');\r | |
484 | expect((rows[1].textContent || rows[1].innerText).replace(/\s/g, '')).toBe('3students30$43.12');\r | |
485 | });\r | |
486 | });\r | |
487 | \r | |
488 | describe('remoteRoot', function () {\r | |
489 | function completeWithData(data) {\r | |
490 | Ext.Ajax.mockComplete({\r | |
491 | status: 200,\r | |
492 | responseText: Ext.JSON.encode(data)\r | |
493 | });\r | |
494 | }\r | |
495 | \r | |
496 | beforeEach(function () {\r | |
497 | MockAjaxManager.addMethods();\r | |
498 | \r | |
499 | createGrid(null, {\r | |
500 | remoteRoot: 'summaryData'\r | |
501 | }, null, {\r | |
502 | remoteSort: true,\r | |
503 | proxy: {\r | |
504 | type: 'ajax',\r | |
505 | url: 'data.json',\r | |
506 | reader: {\r | |
507 | type: 'json',\r | |
508 | rootProperty: 'data'\r | |
509 | }\r | |
510 | },\r | |
511 | grouper: {property: 'student'},\r | |
512 | data: null\r | |
513 | });\r | |
514 | \r | |
515 | store.load();\r | |
516 | \r | |
517 | completeWithData({\r | |
518 | data: data,\r | |
519 | summaryData: [{\r | |
520 | allowance: 67,\r | |
521 | mark: 42,\r | |
522 | student: 'Student 1'\r | |
523 | }, {\r | |
524 | allowance: 100,\r | |
525 | mark: 99,\r | |
526 | student: 'Student 2'\r | |
527 | }],\r | |
528 | total: 4\r | |
529 | });\r | |
530 | });\r | |
531 | \r | |
532 | afterEach(function () {\r | |
533 | MockAjaxManager.removeMethods();\r | |
534 | });\r | |
535 | \r | |
536 | it('should correctly render the data in the view', function () {\r | |
537 | var rows = grid.view.body.query('.x-grid-row-summary');\r | |
538 | \r | |
539 | expect((rows[0].textContent || rows[0].innerText).replace(/\s/g, '')).toBe('Student1students42$67.00');\r | |
540 | expect((rows[1].textContent || rows[1].innerText).replace(/\s/g, '')).toBe('Student2students99$100.00');\r | |
541 | });\r | |
542 | \r | |
543 | it('should create a summaryData object for each group', function () {\r | |
544 | var summaryData = groupingSummary.summaryData;\r | |
545 | \r | |
546 | expect(summaryData['Student 1']).toBeDefined();\r | |
547 | expect(summaryData['Student 2']).toBeDefined();\r | |
548 | });\r | |
549 | \r | |
550 | it('should create a metaGroupCache entry for each group', function () {\r | |
551 | var metaGroupCache = groupingSummary.getCache();\r | |
552 | \r | |
553 | expect(metaGroupCache['Student 1']).toBeDefined();\r | |
554 | expect(metaGroupCache['Student 2']).toBeDefined();\r | |
555 | });\r | |
556 | });\r | |
557 | });\r | |
558 | \r |