]> git.proxmox.com Git - extjs.git/blame - extjs/modern/modern/test/specs/Widget.js
add extjs 6.0.1 sources
[extjs.git] / extjs / modern / modern / test / specs / Widget.js
CommitLineData
6527f429
DM
1describe("Ext.Widget", function() {\r
2\r
3 var w;\r
4\r
5 function makeWidget(cfg) {\r
6 w = new Ext.Widget(cfg);\r
7 return w;\r
8 }\r
9\r
10 afterEach(function() {\r
11 w = Ext.destroy(w);\r
12 });\r
13\r
14 describe("view controllers", function() {\r
15 var Controller, spy\r
16 beforeEach(function() {\r
17 // Suppress console warning about mapping being overridden\r
18 spyOn(Ext.log, 'warn');\r
19\r
20 spy = jasmine.createSpy();\r
21 \r
22 Controller = Ext.define('spec.TestController', {\r
23 extend: 'Ext.app.ViewController',\r
24 alias: 'controller.test',\r
25\r
26 init: spy,\r
27\r
28 someFn: function() {}\r
29 });\r
30 });\r
31 \r
32 afterEach(function() {\r
33 Ext.undefine('spec.TestController');\r
34 spy = Controller = null;\r
35 Ext.Factory.controller.instance.clearCache();\r
36 });\r
37 \r
38 describe("initializing", function() {\r
39 it("should accept an alias string", function() {\r
40 makeWidget({\r
41 controller: 'test'\r
42 }); \r
43 var controller = w.getController(); \r
44 expect(controller instanceof spec.TestController).toBe(true);\r
45 expect(controller.getView()).toBe(w);\r
46 });\r
47 \r
48 it("should accept a controller config", function() {\r
49 makeWidget({\r
50 controller: {\r
51 type: 'test'\r
52 }\r
53 }); \r
54 var controller = w.getController(); \r
55 expect(controller instanceof spec.TestController).toBe(true);\r
56 expect(controller.getView()).toBe(w);\r
57 }); \r
58 \r
59 it("should accept a controller instance", function() {\r
60 var controller = new spec.TestController();\r
61 makeWidget({\r
62 controller: controller\r
63 });\r
64 expect(w.getController()).toBe(controller);\r
65 expect(controller.getView()).toBe(w);\r
66 });\r
67\r
68 it("should be able to pass null", function() {\r
69 makeWidget({\r
70 controller: null\r
71 });\r
72 expect(w.getController()).toBeNull();\r
73 });\r
74\r
75 it("should call the controller init method and pass the view", function() {\r
76 makeWidget({\r
77 controller: 'test'\r
78 });\r
79 expect(spy.callCount).toBe(1);\r
80 expect(spy.mostRecentCall.args[0]).toBe(w);\r
81 });\r
82 }); \r
83 \r
84 it("should destroy the controller when destroying the component", function() {\r
85 makeWidget({\r
86 controller: 'test'\r
87 });\r
88 var controller = w.getController();\r
89 spyOn(controller, 'destroy');\r
90 w.destroy();\r
91 expect(controller.destroy).toHaveBeenCalled();\r
92 });\r
93\r
94 describe("lookupController", function() {\r
95 describe("skipThis: false", function() {\r
96 it("should return null when there is no controller attached to the view", function() {\r
97 makeWidget();\r
98 expect(w.lookupController(false)).toBeNull();\r
99 });\r
100\r
101 it("should return null when there is no controller in the hierarchy", function() {\r
102 var ct = new Ext.container.Container({\r
103 items: {\r
104 xtype: 'component'\r
105 }\r
106 });\r
107 expect(ct.items.first().lookupController(false)).toBeNull();\r
108 ct.destroy();\r
109 });\r
110\r
111 it("should return the controller attached to the component when it is at the root", function() {\r
112 var controller = new spec.TestController();\r
113 makeWidget({\r
114 controller: controller\r
115 });\r
116 expect(w.lookupController(false)).toBe(controller);\r
117 });\r
118\r
119 it("should return the controller attached to the component when it is in a hierarchy", function() {\r
120 var controller = new spec.TestController();\r
121 var ct = new Ext.container.Container({\r
122 items: {\r
123 xtype: 'component',\r
124 controller: controller\r
125 }\r
126 });\r
127 expect(ct.items.first().lookupController(false)).toBe(controller);\r
128 ct.destroy();\r
129 });\r
130\r
131 it("should return a controller above it in the hierarchy", function() {\r
132 var controller = new spec.TestController();\r
133\r
134 var ct = new Ext.container.Container({\r
135 controller: controller,\r
136 items: {\r
137 xtype: 'component'\r
138 }\r
139 });\r
140 expect(ct.items.first().lookupController(false)).toBe(controller);\r
141 ct.destroy();\r
142 });\r
143\r
144 it("should return the closest controller in the hierarchy", function() {\r
145 var controller1 = new spec.TestController(),\r
146 controller2 = new spec.TestController();\r
147\r
148 var ct = new Ext.container.Container({\r
149 controller: controller1,\r
150 items: {\r
151 xtype: 'container',\r
152 controller: controller2,\r
153 items: {\r
154 xtype: 'component',\r
155 itemId: 'x'\r
156 }\r
157 }\r
158 });\r
159 expect(ct.down('#x').lookupController(false)).toBe(controller2);\r
160 ct.destroy();\r
161 });\r
162 });\r
163\r
164 describe("skipThis: true", function() {\r
165 it("should return null when there is no controller attached to the view", function() {\r
166 makeWidget();\r
167 expect(w.lookupController(true)).toBeNull();\r
168 });\r
169\r
170 it("should return null when there is no controller in the hierarchy", function() {\r
171 var ct = new Ext.container.Container({\r
172 items: {\r
173 xtype: 'component'\r
174 }\r
175 });\r
176 expect(ct.items.first().lookupController(true)).toBeNull();\r
177 ct.destroy();\r
178 });\r
179\r
180 it("should not return the controller attached to the component when it is at the root", function() {\r
181 var controller = new spec.TestController();\r
182 makeWidget({\r
183 controller: controller\r
184 });\r
185 expect(w.lookupController(true)).toBeNull();\r
186 });\r
187\r
188 it("should not return the controller attached to the component when it is in a hierarchy and no controllers exist above it", function() {\r
189 var controller = new spec.TestController();\r
190 var ct = new Ext.container.Container({\r
191 items: {\r
192 xtype: 'component',\r
193 controller: controller\r
194 }\r
195 });\r
196 expect(ct.items.first().lookupController(true)).toBeNull();\r
197 ct.destroy();\r
198 });\r
199\r
200 it("should return a controller above it in the hierarchy", function() {\r
201 var controller = new spec.TestController();\r
202\r
203 var ct = new Ext.container.Container({\r
204 controller: controller,\r
205 items: {\r
206 xtype: 'component'\r
207 }\r
208 });\r
209 expect(ct.items.first().lookupController(true)).toBe(controller);\r
210 ct.destroy();\r
211 });\r
212\r
213 it("should return the closest controller in the hierarchy", function() {\r
214 var controller1 = new spec.TestController(),\r
215 controller2 = new spec.TestController();\r
216\r
217 var ct = new Ext.container.Container({\r
218 controller: controller1,\r
219 items: {\r
220 xtype: 'container',\r
221 controller: controller2,\r
222 items: {\r
223 xtype: 'component',\r
224 itemId: 'x'\r
225 }\r
226 }\r
227 });\r
228 expect(ct.down('#x').lookupController(true)).toBe(controller2);\r
229 ct.destroy();\r
230 });\r
231 });\r
232\r
233 it("should default to skipThis: false", function() {\r
234 var controller = new spec.TestController();\r
235 makeWidget({\r
236 controller: controller\r
237 });\r
238 expect(w.lookupController()).toBe(controller);\r
239 });\r
240 });\r
241 });\r
242\r
243 describe("viewmodel", function() {\r
244 var spy, order, called;\r
245\r
246 beforeEach(function() {\r
247 called = false;\r
248 Ext.define('spec.ViewModel', {\r
249 extend: 'Ext.app.ViewModel',\r
250 alias: 'viewmodel.test',\r
251 constructor: function() {\r
252 this.callParent(arguments);\r
253 order.push(this.getId());\r
254 called = true;\r
255 }\r
256 });\r
257 order = [];\r
258 });\r
259\r
260 afterEach(function() {\r
261 Ext.undefine('spec.ViewModel');\r
262 Ext.Factory.viewModel.instance.clearCache();\r
263 order = null;\r
264 called = false;\r
265 });\r
266\r
267 it("should accept a string alias", function() {\r
268 makeWidget({\r
269 viewModel: 'test'\r
270 });\r
271 expect(w.getViewModel() instanceof spec.ViewModel).toBe(true);\r
272 });\r
273\r
274 it("should accept an object config", function() {\r
275 makeWidget({\r
276 viewModel: {\r
277 type: 'test'\r
278 }\r
279 });\r
280 expect(w.getViewModel() instanceof spec.ViewModel).toBe(true);\r
281 });\r
282\r
283 it("should accept an object instance", function() {\r
284 var vm = new spec.ViewModel();\r
285 makeWidget({\r
286 viewModel: vm\r
287 });\r
288 expect(w.getViewModel()).toBe(vm);\r
289 });\r
290\r
291 describe("calling initViewController", function() {\r
292 var TestController = Ext.define(null, {\r
293 extend: 'Ext.app.ViewController'\r
294 });\r
295\r
296 it("should call initViewController when creating an instance", function() {\r
297 var ctrl = new TestController();\r
298 spyOn(ctrl, 'initViewModel');\r
299 makeWidget({\r
300 controller: ctrl,\r
301 viewModel: {\r
302 type: 'test'\r
303 },\r
304 bind: {\r
305 width: '{foo}'\r
306 }\r
307 });\r
308 expect(ctrl.initViewModel.callCount).toBe(1);\r
309 expect(ctrl.initViewModel).toHaveBeenCalledWith(w.getViewModel());\r
310 });\r
311 });\r
312\r
313 describe("hierarchy", function() {\r
314 var ct, inner;\r
315\r
316 function vm(id) {\r
317 return {\r
318 type: 'test',\r
319 id: id\r
320 };\r
321 }\r
322\r
323 function makeHierarchy(bind) {\r
324 ct = new Ext.container.Container({\r
325 viewModel: vm('top'),\r
326 id: 'top',\r
327 items: {\r
328 xtype: 'container',\r
329 id: 'middle',\r
330 viewModel: vm('middle'),\r
331 items: {\r
332 xtype: 'component',\r
333 id: 'bottom',\r
334 viewModel: vm('bottom'),\r
335 bind: bind || null\r
336 }\r
337 }\r
338 });\r
339 inner = ct.items.first();\r
340 w = inner.items.first();\r
341 }\r
342\r
343 afterEach(function() {\r
344 ct.destroy();\r
345 ct = inner = null;\r
346 });\r
347\r
348 it("should initialize viewmodels top down", function() {\r
349 makeHierarchy();\r
350 w.getViewModel();\r
351 expect(order).toEqual(['top', 'middle', 'bottom']);\r
352 });\r
353 });\r
354\r
355 describe("session", function() {\r
356 it("should attach the view model to the session", function() {\r
357 var session = new Ext.data.Session();\r
358 makeWidget({\r
359 session: session,\r
360 viewModel: {}\r
361 });\r
362 expect(w.getViewModel().getSession()).toBe(session);\r
363 });\r
364\r
365 it("should attach the view model to a session higher up in the hierarchy", function() {\r
366 var session = new Ext.data.Session();\r
367 var ct = new Ext.container.Container({\r
368 session: session,\r
369 items: {\r
370 xtype: 'component',\r
371 viewModel: true\r
372 }\r
373 });\r
374 expect(ct.items.first().getViewModel().getSession()).toBe(session);\r
375 ct.destroy();\r
376 });\r
377\r
378 it("should use an attached session at the same level instead of a higher one", function() {\r
379 var session1 = new Ext.data.Session(),\r
380 session2 = new Ext.data.Session();\r
381\r
382 var ct = new Ext.container.Container({\r
383 session: session1,\r
384 items: {\r
385 xtype: 'component',\r
386 session: session2,\r
387 viewModel: {}\r
388 }\r
389 });\r
390 expect(ct.items.first().getViewModel().getSession()).toBe(session2);\r
391 ct.destroy();\r
392 });\r
393 });\r
394 });\r
395\r
396 describe("session", function() {\r
397 it("should not have a session by default", function() {\r
398 makeWidget();\r
399 expect(w.getSession()).toBeNull();\r
400 });\r
401\r
402 it("should use a passed session", function() {\r
403 var session = new Ext.data.Session();\r
404 makeWidget({\r
405 session: session\r
406 });\r
407 expect(w.getSession()).toBe(session);\r
408 });\r
409\r
410 it("should create a session when session: true is specified", function() {\r
411 makeWidget({\r
412 session: true\r
413 });\r
414 expect(w.getSession().isSession).toBe(true);\r
415 });\r
416\r
417 it("should destroy the session when the component is destroyed", function() {\r
418 var session = new Ext.data.Session(),\r
419 spy = spyOn(session, 'destroy').andCallThrough();\r
420\r
421 makeWidget({\r
422 session: session\r
423 });\r
424 w.destroy();\r
425 expect(spy).toHaveBeenCalled();\r
426 });\r
427\r
428 it("should not destroy the session with autoDestroy: false", function() {\r
429 var session = new Ext.data.Session({\r
430 autoDestroy: false\r
431 });\r
432 var spy = spyOn(session, 'destroy').andCallThrough();\r
433 makeWidget({\r
434 session: session\r
435 });\r
436 w.destroy();\r
437 expect(spy).not.toHaveBeenCalled();\r
438 session.destroy();\r
439 });\r
440\r
441 describe("hierarchy", function() {\r
442 it("should use a parent session", function() {\r
443 var session = new Ext.data.Session();\r
444\r
445 var ct = new Ext.container.Container({\r
446 session: session,\r
447 items: {\r
448 xtype: 'component'\r
449 }\r
450 });\r
451 expect(ct.items.first().lookupSession()).toBe(session);\r
452 \r
453 ct.destroy();\r
454 });\r
455\r
456 it("should spawn a session from the parent if specifying session: true", function() {\r
457 var session = new Ext.data.Session();\r
458\r
459 var ct = new Ext.container.Container({\r
460 session: session,\r
461 items: {\r
462 xtype: 'component',\r
463 session: true\r
464 }\r
465 });\r
466\r
467 var child = ct.items.first().getSession();\r
468 expect(child.getParent()).toBe(session);\r
469 \r
470 ct.destroy();\r
471 });\r
472 });\r
473 });\r
474\r
475 describe("bind", function() {\r
476 it("should be able to bind to multiple properties", function() {\r
477 makeWidget({\r
478 viewModel: {\r
479 data: {\r
480 width: 200,\r
481 height: 200\r
482 }\r
483 },\r
484 bind: {\r
485 width: '{width}',\r
486 height: '{height}'\r
487 }\r
488 });\r
489 w.getViewModel().notify();\r
490 expect(w.getWidth()).toBe(200);\r
491 expect(w.getHeight()).toBe(200);\r
492 });\r
493\r
494 describe("twoWayBindable", function() {\r
495 var Cls, viewModel;\r
496\r
497 beforeEach(function() {\r
498 Cls = Ext.define(null, {\r
499 extend: 'Ext.Component',\r
500 config: {\r
501 customA: 1,\r
502 customB: null,\r
503 customC: undefined,\r
504 customD: 'foo'\r
505 },\r
506 twoWayBindable: ['customB', 'customC', 'customD']\r
507 });\r
508 });\r
509\r
510 afterEach(function() {\r
511 viewModel = Cls = null;\r
512 });\r
513\r
514 function makeCls(cfg) {\r
515 w = new Cls(Ext.apply({\r
516 }, cfg));\r
517 viewModel = w.getViewModel();\r
518 }\r
519\r
520 it("should not be twoWayBindable by default", function() {\r
521 makeCls({\r
522 viewModel: {\r
523 data: {\r
524 a: 1\r
525 }\r
526 },\r
527 bind: {\r
528 customA: '{a}'\r
529 }\r
530 });\r
531 viewModel.notify();\r
532 w.setCustomA('Foo');\r
533 expect(viewModel.get('a')).toBe(1);\r
534 });\r
535\r
536 it("should not cause an error if a twoWayBindable is not bound", function() {\r
537 expect(function() {\r
538 makeCls({\r
539 viewModel: {},\r
540 bind: {}\r
541 });\r
542 }).not.toThrow();\r
543 });\r
544\r
545 describe("when the binding has not fired", function() {\r
546 it("should not publish when the value is undefined", function() {\r
547 makeCls({\r
548 viewModel: {\r
549 data: {\r
550 c: 100\r
551 }\r
552 },\r
553 bind: {\r
554 customC: '{c}'\r
555 }\r
556 });\r
557 expect(viewModel.get('c')).toBe(100);\r
558 viewModel.notify();\r
559 expect(w.getCustomC()).toBe(100);\r
560 });\r
561\r
562 it("should not publish when the value is null", function() {\r
563 makeCls({\r
564 viewModel: {\r
565 data: {\r
566 b: 200\r
567 }\r
568 },\r
569 bind: {\r
570 customB: '{b}'\r
571 }\r
572 });\r
573 expect(viewModel.get('b')).toBe(200);\r
574 viewModel.notify();\r
575 expect(w.getCustomB()).toBe(200);\r
576 });\r
577\r
578 it("should not publish when the value is equal to the class default", function() {\r
579 makeCls({\r
580 viewModel: {\r
581 data: {\r
582 d: 'bar'\r
583 }\r
584 },\r
585 bind: {\r
586 customD: '{d}'\r
587 }\r
588 });\r
589 expect(viewModel.get('d')).toBe('bar');\r
590 viewModel.notify();\r
591 expect(w.getCustomD()).toBe('bar');\r
592 });\r
593\r
594 it("should not publish when the value is equal to the instance config value", function() {\r
595 makeCls({\r
596 customD: 'baz',\r
597 viewModel: {\r
598 data: {\r
599 d: 'bar'\r
600 }\r
601 },\r
602 bind: {\r
603 customD: '{d}'\r
604 }\r
605 });\r
606 expect(viewModel.get('d')).toBe('bar');\r
607 viewModel.notify();\r
608 expect(w.getCustomD()).toBe('bar');\r
609 });\r
610\r
611 it("should publish any other value", function() {\r
612 makeCls({\r
613 viewModel: {\r
614 data: {\r
615 d: 'bar'\r
616 }\r
617 },\r
618 bind: {\r
619 customD: '{d}'\r
620 }\r
621 });\r
622 w.setCustomD('new');\r
623 expect(viewModel.get('d')).toBe('new');\r
624 });\r
625 });\r
626\r
627 describe("when the binding has fired", function() {\r
628 it("should publish undefined", function() {\r
629 makeCls({\r
630 viewModel: {\r
631 b: 'x'\r
632 },\r
633 bind: {\r
634 customB: '{b}'\r
635 }\r
636 });\r
637 viewModel.notify();\r
638 w.setCustomB(undefined);\r
639 // ViewModel converts undefined to null\r
640 expect(viewModel.get('b')).toBeNull();\r
641 });\r
642\r
643 it("should publish null", function() {\r
644 makeCls({\r
645 viewModel: {\r
646 b: 'x'\r
647 },\r
648 bind: {\r
649 customB: '{b}'\r
650 }\r
651 });\r
652 viewModel.notify();\r
653 w.setCustomB(null);\r
654 expect(viewModel.get('b')).toBeNull();\r
655 });\r
656\r
657 it("should publish the class default", function() {\r
658 makeCls({\r
659 viewModel: {\r
660 data: {\r
661 d: 'bar'\r
662 }\r
663 },\r
664 bind: {\r
665 customD: '{d}'\r
666 }\r
667 });\r
668 viewModel.notify();\r
669 w.setCustomD('foo');\r
670 expect(viewModel.get('d')).toBe('foo');\r
671 });\r
672\r
673 it("should publish the instance config value", function() {\r
674 makeCls({\r
675 customD: 'baz',\r
676 viewModel: {\r
677 data: {\r
678 d: 'bar'\r
679 }\r
680 },\r
681 bind: {\r
682 customD: '{d}'\r
683 }\r
684 });\r
685 viewModel.notify();\r
686 w.setCustomD('baz');\r
687 expect(viewModel.get('d')).toBe('baz');\r
688 });\r
689 });\r
690 });\r
691 });\r
692\r
693});