]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/test/specs/tab/Panel.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / test / specs / tab / Panel.js
CommitLineData
6527f429
DM
1describe("Ext.tab.Panel", function() {\r
2 var tabPanel, fakeTabBar;\r
3\r
4 function createTabPanel(config) {\r
5 tabPanel = Ext.create(Ext.apply({\r
6 xtype: 'tabpanel',\r
7 renderTo: Ext.getBody()\r
8 }, config));\r
9\r
10 return tabPanel;\r
11 }\r
12\r
13 //creates a tab panel with x children\r
14 function createTabPanelWithTabs(count, config) {\r
15 var i, items = [];\r
16\r
17 for (i = 0; i < count; i++) {\r
18 items[i] = {\r
19 xtype: 'panel',\r
20 html : 'test ' + (i + 1),\r
21 title: 'test ' + (i + 1),\r
22 itemId: 'item' + (i + 1)\r
23 };\r
24 }\r
25\r
26 return createTabPanel(Ext.apply({}, config, {\r
27 items: items\r
28 }));\r
29 }\r
30\r
31 afterEach(function() {\r
32 if (tabPanel) {\r
33 tabPanel = Ext.destroy(tabPanel);\r
34 }\r
35 });\r
36\r
37 describe("active tab config on init", function() {\r
38 it("should ignore the activeTab as a string ID if it doesn't exist", function() {\r
39 createTabPanelWithTabs(3, {\r
40 activeTab: 'foo'\r
41 });\r
42 expect(tabPanel.getActiveTab()).toBeUndefined();\r
43 });\r
44 it("should ignore the activeTab as a numeric index if it doesn't exist", function() {\r
45 createTabPanelWithTabs(3, {\r
46 activeTab: 4\r
47 });\r
48 expect(tabPanel.getActiveTab()).toBeUndefined();\r
49 });\r
50 it("should activate the activeTab by string ID if it does exist", function() {\r
51 var foo = Ext.id(null, 'foo-'),\r
52 bar = Ext.id(null, 'bar-');\r
53\r
54 createTabPanelWithTabs(3, {\r
55 items: [{\r
56 id: bar\r
57 }, {\r
58 id: foo\r
59 }],\r
60 activeTab: foo\r
61 });\r
62 expect(tabPanel.getActiveTab().id).toEqual(foo);\r
63 });\r
64 it("should activate the activeTab by index if it does exist", function(){\r
65 var foo = Ext.id(null, 'foo-'),\r
66 bar = Ext.id(null, 'bar-');\r
67\r
68 createTabPanelWithTabs(3, {\r
69 items: [{\r
70 id: bar\r
71 }, {\r
72 id: foo\r
73 }],\r
74 activeTab: 1\r
75 });\r
76 expect(tabPanel.getActiveTab().id).toEqual(foo);\r
77 });\r
78 it("should not set an active tab if null", function() {\r
79 createTabPanelWithTabs(3, {\r
80 activeTab: null\r
81 });\r
82 expect(tabPanel.getActiveTab()).toBeUndefined();\r
83 });\r
84 it("should set the first child tab as the active tab if none is configured", function() {\r
85 createTabPanelWithTabs(3, {\r
86 });\r
87 expect(tabPanel.getActiveTab()).toBe(tabPanel.items.getAt(0));\r
88 });\r
89 });\r
90\r
91 describe("activating other tabs on tab close", function() {\r
92 var tb;\r
93 it("should activate the next tab", function() {\r
94 createTabPanelWithTabs(6, {\r
95 renderTo: document.body,\r
96 activeTab: 4\r
97 });\r
98 tb = tabPanel.tabBar;\r
99 tb.closeTab(tb.items.items[4]);\r
100 expect(tabPanel.items.indexOf(tabPanel.getActiveTab())).toEqual(4);\r
101 });\r
102 it("should activate the previously active tab", function() {\r
103 createTabPanelWithTabs(6, {\r
104 renderTo: document.body,\r
105 activeTab: 5\r
106 });\r
107 tb = tabPanel.tabBar;\r
108 tabPanel.setActiveTab(0);\r
109 tabPanel.setActiveTab(4);\r
110 tabPanel.tabBar.closeTab(tb.items.items[4]);\r
111 expect(tabPanel.items.indexOf(tabPanel.getActiveTab())).toEqual(0);\r
112 });\r
113 it("should activate the new first tab when closing the first", function() {\r
114 createTabPanelWithTabs(6, {\r
115 renderTo: document.body,\r
116 activeTab: 0\r
117 });\r
118 tb = tabPanel.tabBar;\r
119 tabPanel.tabBar.closeTab(tb.items.items[0]);\r
120 expect(tabPanel.items.indexOf(tabPanel.getActiveTab())).toEqual(0);\r
121 });\r
122 });\r
123 \r
124 describe("the tabBar", function() {\r
125 beforeEach(function() {\r
126 fakeTabBar = {\r
127 something: 'yea'\r
128 };\r
129 });\r
130 \r
131 it("should be referenced as .tabBar", function() {\r
132 createTabPanel();\r
133 expect(tabPanel.tabBar).toBeDefined();\r
134 });\r
135 \r
136 it("should be docked to the top", function() {\r
137 createTabPanel();\r
138 expect(tabPanel.tabBar.dock).toEqual('top');\r
139 });\r
140 \r
141 it("should be accessible through getTabBar()", function() {\r
142 createTabPanel();\r
143 expect(tabPanel.getTabBar()).toBeDefined();\r
144 });\r
145 \r
146 it("should accept additional config", function() {\r
147 createTabPanel({\r
148 tabBar: {\r
149 someConfig: 'something'\r
150 }\r
151 });\r
152 \r
153 expect(tabPanel.tabBar.someConfig).toEqual('something');\r
154 });\r
155 \r
156 xdescribe("if there were no other dockedItems", function() {\r
157 beforeEach(function() {\r
158 createTabPanel();\r
159 });\r
160\r
161 it("should create the dockedItems MixedCollection", function() {\r
162 expect(tabPanel.dockedItems instanceof Ext.util.MixedCollection).toBe(true);\r
163 });\r
164 \r
165 it("should place the tabBar in the array", function() {\r
166 expect(tabPanel.dockedItems.items[0]).toEqual(tabPanel.tabBar);\r
167 });\r
168 });\r
169 \r
170 describe("if there was an array of dockedItems", function() {\r
171 beforeEach(function() {\r
172 createTabPanel({\r
173 dockedItems: [\r
174 {\r
175 xtype: 'panel',\r
176 html : 'test',\r
177 dock : 'top'\r
178 }\r
179 ]\r
180 });\r
181 });\r
182 \r
183 it("should add the tabBar to the dockedItems", function() {\r
184 expect(tabPanel.dockedItems.length).toEqual(2);\r
185 });\r
186 \r
187 it("should place the tabBar as the last item in the array", function() {\r
188 expect(tabPanel.dockedItems.items[1]).toEqual(tabPanel.tabBar);\r
189 });\r
190 });\r
191 \r
192 describe("if there was a single dockedItem, not in an array", function() {\r
193 beforeEach(function() {\r
194 createTabPanel({\r
195 dockedItems: {\r
196 xtype: 'panel',\r
197 html : 'test',\r
198 dock : 'top'\r
199 }\r
200 });\r
201 });\r
202 \r
203 xit("should turn the dockedItems into an array", function() {\r
204 expect(tabPanel.dockedItems instanceof Ext.util.MixedCollection).toBe(true);\r
205 });\r
206 \r
207 it("should add the tabBar to the dockedItems", function() {\r
208 expect(tabPanel.dockedItems.length).toEqual(2);\r
209 });\r
210 \r
211 it("should place the tabBar as the last item in the array", function() {\r
212 expect(tabPanel.dockedItems.items[1]).toEqual(tabPanel.tabBar);\r
213 });\r
214 });\r
215\r
216 describe("non tab items", function() {\r
217 it("should not cause an error", function() {\r
218 expect(function() {\r
219 createTabPanel({\r
220 tabBar: {\r
221 items: [{\r
222 xtype: 'button',\r
223 text: 'Foo'\r
224 }]\r
225 },\r
226 items: [{\r
227 title: 'Bar'\r
228 }, {\r
229 title: 'Baz'\r
230 }]\r
231 });\r
232 }).not.toThrow();\r
233 var items = tabPanel.tabBar.items;\r
234 expect(items.getCount()).toBe(3);\r
235 expect(items.last().getText()).toBe('Foo');\r
236 });\r
237\r
238 it("should not cause an error when using tabPosition", function() {\r
239 expect(function() {\r
240 createTabPanel({\r
241 tabPosition: 'bottom',\r
242 tabBar: {\r
243 items: [{\r
244 xtype: 'button',\r
245 text: 'Foo'\r
246 }]\r
247 },\r
248 items: [{\r
249 title: 'Bar'\r
250 }, {\r
251 title: 'Baz'\r
252 }]\r
253 });\r
254 }).not.toThrow();\r
255 var items = tabPanel.tabBar.items;\r
256 expect(items.getCount()).toBe(3);\r
257 expect(items.last().getText()).toBe('Foo');\r
258 });\r
259\r
260 it("should allow a click on a button", function() {\r
261 var spy = jasmine.createSpy('click'),\r
262 btn;\r
263 \r
264 runs(function() {\r
265 createTabPanel({\r
266 tabBar: {\r
267 items: [{\r
268 xtype: 'button',\r
269 itemId: 'theButton',\r
270 text: 'Foo'\r
271 }]\r
272 },\r
273 items: [{\r
274 title: 'Bar'\r
275 }, {\r
276 title: 'Baz'\r
277 }]\r
278 });\r
279 btn = tabPanel.down('#theButton');\r
280\r
281 btn.on('click', spy);\r
282 });\r
283 \r
284 runs(function() {\r
285 expect(function() {\r
286 jasmine.fireMouseEvent(btn.getEl(), 'click');\r
287 }).not.toThrow();\r
288 });\r
289 \r
290 waitsFor(function() { return !!spy.callCount }, 'spy to be called', 100);\r
291 \r
292 runs(function() {\r
293 expect(spy).toHaveBeenCalled();\r
294 });\r
295 });\r
296 });\r
297 });\r
298 \r
299 describe("the layout", function() {\r
300 beforeEach(function() {\r
301 createTabPanel({\r
302 layout: {\r
303 someConfig: 'something'\r
304 }\r
305 });\r
306 });\r
307 \r
308 it("should be a card layout", function() {\r
309 expect(tabPanel.layout instanceof Ext.layout.CardLayout).toBe(true);\r
310 });\r
311 \r
312 it("should accept additional config", function() {\r
313 expect(tabPanel.layout.someConfig).toEqual('something');\r
314 });\r
315 });\r
316\r
317 describe("after initialization", function() {\r
318 it("should have created a tab for each child component", function() {\r
319 var count = 0;\r
320 createTabPanelWithTabs(2);\r
321 tabPanel.getTabBar().items.each(function(item) {\r
322 if (item.is('tab')) {\r
323 count = count + 1;\r
324 }\r
325 });\r
326 expect(count).toEqual(2);\r
327 });\r
328\r
329 describe('activeTab config', function () {\r
330 it('if none, should set the first tab as active by default', function() {\r
331 createTabPanelWithTabs(2);\r
332\r
333 expect(tabPanel.getActiveTab()).toEqual(tabPanel.items.items[0]);\r
334 });\r
335\r
336 it('if undefined, should call setActiveTab with the correct item', function() {\r
337 createTabPanelWithTabs(2, {\r
338 activeTab: undefined\r
339 });\r
340\r
341 expect(tabPanel.getActiveTab()).toEqual(tabPanel.items.items[0]);\r
342 });\r
343\r
344 it('if set, should call setActiveTab with the correct item', function() {\r
345 createTabPanelWithTabs(2, {\r
346 activeTab: 1\r
347 });\r
348\r
349 expect(tabPanel.getActiveTab()).toEqual(tabPanel.items.items[1]);\r
350 });\r
351\r
352 it('if null, should not call setActiveTab', function() {\r
353 createTabPanelWithTabs(2, {\r
354 activeTab: null\r
355 });\r
356\r
357 expect(tabPanel.getActiveTab()).toEqual(null);\r
358 });\r
359\r
360 it('if called when there are no tabs it should set activeTab as undefined', function() {\r
361 createTabPanelWithTabs(0);\r
362 tabPanel.setActiveTab(5);\r
363\r
364 expect(tabPanel.getActiveTab()).toEqual(undefined);\r
365 expect(tabPanel.activeTab).toBeUndefined();\r
366 });\r
367 });\r
368 });\r
369\r
370 describe("modifying items", function() {\r
371 describe("tab configuration", function() {\r
372 var tabBar;\r
373 \r
374 function addChild(config) {\r
375 return tabPanel.add(Ext.apply({\r
376 xtype: 'panel',\r
377 title: 'new',\r
378 html : 'New Panel',\r
379 itemId: 'newItem'\r
380 }, config));\r
381 }\r
382 \r
383 beforeEach(function() {\r
384 createTabPanel();\r
385 \r
386 tabBar = tabPanel.getTabBar();\r
387 });\r
388 \r
389 it("should give the tab a reference to the card", function() {\r
390 var newChild = addChild(), \r
391 newTab = tabBar.items.first();\r
392 \r
393 expect(newTab.card).toEqual(newChild);\r
394 });\r
395 \r
396 it("should give the tab a reference to the tabBar", function() {\r
397 var newChild = addChild(), \r
398 newTab = tabBar.items.first();\r
399 \r
400 expect(newTab.tabBar).toEqual(tabBar);\r
401 });\r
402 \r
403 it("should not overwrite closeText with undefined", function() {\r
404 var tab = addChild().tab;\r
405 \r
406 expect(tab.closeText).toBe('Close Tab');\r
407 });\r
408 \r
409 it("should overwrite closeText when specified in tab config", function() {\r
410 var tab = addChild({ closeText: 'foo bar' }).tab;\r
411 \r
412 expect(tab.closeText).toBe('foo bar');\r
413 });\r
414 });\r
415\r
416 it("should append a tab to the end", function() {\r
417 createTabPanelWithTabs(3);\r
418 var item = tabPanel.add({\r
419 title: 'foo'\r
420 }), tab, items;\r
421\r
422 items = tabPanel.getTabBar().items;\r
423 tab = items.getAt(3);\r
424 expect(items.getCount()).toBe(4);\r
425 expect(tab.text).toBe('foo');\r
426 expect(item.tab).toBe(tab);\r
427 });\r
428\r
429 it("should insert a tab at the specified index", function() {\r
430 createTabPanelWithTabs(3);\r
431 var item = tabPanel.insert(1, {\r
432 title: 'foo'\r
433 }), items, tab;\r
434\r
435 items = tabPanel.getTabBar().items;\r
436 tab = items.getAt(1);\r
437 expect(items.getCount()).toBe(4);\r
438 expect(tab.text).toBe('foo');\r
439 expect(item.tab).toBe(tab);\r
440 });\r
441\r
442 it("should move the tab when using moveBefore", function() {\r
443 createTabPanelWithTabs(5);\r
444\r
445 var item = tabPanel.down('#item1'),\r
446 items, tab;\r
447\r
448 tabPanel.moveBefore(item, tabPanel.down('#item4'));\r
449\r
450 items = tabPanel.getTabBar().items;\r
451 tab = items.getAt(2);\r
452 expect(items.getCount()).toBe(5);\r
453 expect(tab.text).toBe('test 1');\r
454 expect(item.tab).toBe(tab);\r
455 });\r
456\r
457 it("should move the tab when using moveAfter", function() {\r
458 createTabPanelWithTabs(5);\r
459\r
460 var item = tabPanel.down('#item1'),\r
461 items, tab;\r
462\r
463 tabPanel.moveAfter(item, tabPanel.down('#item3'));\r
464\r
465 items = tabPanel.getTabBar().items;\r
466 tab = items.getAt(2);\r
467 expect(items.getCount()).toBe(5);\r
468 expect(tab.text).toBe('test 1');\r
469 expect(item.tab).toBe(tab);\r
470 });\r
471\r
472 it("should remove the tab when removing", function() {\r
473 createTabPanelWithTabs(3);\r
474\r
475 tabPanel.remove(1);\r
476 var items = tabPanel.getTabBar().items;\r
477 expect(items.getCount()).toBe(2);\r
478 expect(items.getAt(0).text).toBe('test 1');\r
479 expect(items.getAt(1).text).toBe('test 3');\r
480 });\r
481 });\r
482 \r
483 describe("setting the active tab", function() {\r
484 var waitForFocus = jasmine.waitForFocus,\r
485 pressArrow = jasmine.pressArrowKey,\r
486 expectFocused = jasmine.expectFocused,\r
487 pressKey = jasmine.pressKey,\r
488 item1, item2, item3, item4,\r
489 tab1, tab2, tab3, tab4;\r
490\r
491 beforeEach(function() {\r
492 createTabPanelWithTabs(4);\r
493 item1 = tabPanel.items.getAt(0);\r
494 item2 = tabPanel.items.getAt(1);\r
495 item3 = tabPanel.items.getAt(2);\r
496 item4 = tabPanel.items.getAt(3);\r
497 \r
498 tab1 = item1.tab;\r
499 tab2 = item2.tab;\r
500 tab3 = item3.tab;\r
501 tab4 = item4.tab;\r
502 });\r
503\r
504 afterEach(function() {\r
505 tab1 = tab2 = tab3 = tab4 = null;\r
506 item1 = item2 = item3 = item4 = null;\r
507 });\r
508 \r
509 describe("programmatically", function() {\r
510 describe("parameter types", function() {\r
511 it("should accept a component index", function() {\r
512 tabPanel.setActiveTab(2);\r
513 expect(tabPanel.getActiveTab()).toBe(item3);\r
514 });\r
515\r
516 it("should accept an itemId", function() {\r
517 tabPanel.setActiveTab('item2');\r
518 expect(tabPanel.getActiveTab()).toBe(item2);\r
519 });\r
520\r
521 it("should accept an instance", function() {\r
522 tabPanel.setActiveTab('item2');\r
523 expect(tabPanel.getActiveTab()).toBe(tabPanel.down('#item2'));\r
524 });\r
525\r
526 it("should accept an object config and add it", function() {\r
527 tabPanel.setActiveTab({\r
528 itemId: 'item5'\r
529 });\r
530 expect(tabPanel.getActiveTab()).toBe(tabPanel.down('#item5'));\r
531 });\r
532\r
533 it("should leave the current active tab if the component is not found", function() {\r
534 tabPanel.setActiveTab(9);\r
535 expect(tabPanel.getActiveTab()).toBe(item1);\r
536 });\r
537 });\r
538\r
539 describe("return value", function() {\r
540 it("should return the current tab if the component could not be found", function() {\r
541 expect(tabPanel.setActiveTab(9)).toBe(item1);\r
542 });\r
543\r
544 it("should return the same tab if setting the current tab active", function() {\r
545 expect(tabPanel.setActiveTab(item1)).toBe(item1);\r
546 });\r
547\r
548 it("should return the current tab if the tab change is vetoed", function() {\r
549 tabPanel.on('beforetabchange', function() {\r
550 return false;\r
551 });\r
552 expect(tabPanel.setActiveTab(item3)).toBe(item1);\r
553 });\r
554\r
555 it("should return the new active item", function() {\r
556 expect(tabPanel.setActiveTab(item4)).toBe(item4);\r
557 });\r
558\r
559 it("should return a newly added item", function() {\r
560 var item = tabPanel.setActiveTab({\r
561 itemId: 'item5'\r
562 });\r
563 expect(item).toBe(tabPanel.down('#item5'));\r
564 });\r
565 });\r
566\r
567 describe("events", function() {\r
568 var beforeSpy, spy;\r
569\r
570 beforeEach(function() {\r
571 beforeSpy = jasmine.createSpy();\r
572 spy = jasmine.createSpy();\r
573 tabPanel.on('beforetabchange', beforeSpy);\r
574 tabPanel.on('tabchange', spy);\r
575 });\r
576\r
577 afterEach(function() {\r
578 beforeSpy = spy = null;\r
579 });\r
580\r
581 describe("when the tab cannot be found", function() {\r
582 it("should not fire beforetabchange or tabchange", function() {\r
583 tabPanel.setActiveTab(9);\r
584 expect(beforeSpy).not.toHaveBeenCalled();\r
585 expect(spy).not.toHaveBeenCalled();\r
586 });\r
587 });\r
588\r
589 describe("when setting the same tab", function() {\r
590 it("should not fire beforetabchange or tabchange", function() {\r
591 tabPanel.setActiveTab(item1);\r
592 expect(beforeSpy).not.toHaveBeenCalled();\r
593 expect(spy).not.toHaveBeenCalled();\r
594 });\r
595 });\r
596\r
597 describe("when setting a new (existing) tab", function() {\r
598 it("should fire beforetabchange and pass the tabpanel, new tab & old tab", function() {\r
599 tabPanel.setActiveTab(item2);\r
600 expect(beforeSpy.callCount).toBe(1);\r
601 var args = beforeSpy.mostRecentCall.args;\r
602 expect(args[0]).toBe(tabPanel);\r
603 expect(args[1]).toBe(item2);\r
604 expect(args[2]).toBe(item1);\r
605 });\r
606\r
607 it("should not modify the activeTab if beforetabchange returns false", function() {\r
608 beforeSpy.andReturn(false);\r
609 tabPanel.setActiveTab(item2);\r
610 expect(spy).not.toHaveBeenCalled();\r
611 expect(tabPanel.getActiveTab()).toBe(item1);\r
612 });\r
613\r
614 it("should fire the tabchange event and pass the tabpanel, new tab & old tab", function() {\r
615 tabPanel.setActiveTab(item3);\r
616 expect(spy.callCount).toBe(1);\r
617 var args = spy.mostRecentCall.args;\r
618 expect(args[0]).toBe(tabPanel);\r
619 expect(args[1]).toBe(item3);\r
620 expect(args[2]).toBe(item1);\r
621 });\r
622 });\r
623\r
624 describe("when setting a new (config) tab", function() {\r
625 it("should pass the new item instance", function() {\r
626 tabPanel.setActiveTab({\r
627 itemId: 'item5'\r
628 });\r
629 var item = tabPanel.down('#item5');\r
630 expect(beforeSpy.mostRecentCall.args[1]).toBe(item);\r
631 expect(spy.mostRecentCall.args[1]).toBe(item);\r
632 });\r
633 });\r
634\r
635 describe("tab visibility", function() {\r
636 it("should not have the new tab visible when beforetabchange fires", function() {\r
637 var cardVisible, active;\r
638 beforeSpy.andCallFake(function() {\r
639 cardVisible = item2.isVisible();\r
640 active = tabPanel.getTabBar().activeTab;\r
641 });\r
642 tabPanel.setActiveTab(item2);\r
643 expect(cardVisible).toBe(false);\r
644 expect(active).toBe(item1.tab);\r
645 });\r
646\r
647 it("should have the new tab visible when tabchange fires", function() {\r
648 var cardVisible, active;\r
649 spy.andCallFake(function() {\r
650 cardVisible = item2.isVisible();\r
651 active = tabPanel.getTabBar().activeTab;\r
652 });\r
653 tabPanel.setActiveTab(item2);\r
654 expect(cardVisible).toBe(true);\r
655 expect(active).toBe(item2.tab);\r
656 });\r
657 });\r
658\r
659 it("should not affect layouts if beforetabchange is vetoed", function() {\r
660 var other = new Ext.Component({\r
661 renderTo: Ext.getBody(),\r
662 width: 50,\r
663 height: 50\r
664 });\r
665\r
666 tabPanel.on('beforetabchange', function() {\r
667 other.setSize(100, 100);\r
668 return false;\r
669 });\r
670\r
671 tabPanel.setActiveTab(item2);\r
672\r
673 expect(other.getWidth()).toBe(100);\r
674 expect(other.getHeight()).toBe(100);\r
675\r
676 other.destroy();\r
677 });\r
678 });\r
679\r
680 describe("tab bar", function() {\r
681 var bar;\r
682\r
683 beforeEach(function() {\r
684 bar = tabPanel.getTabBar();\r
685 });\r
686\r
687 afterEach(function() {\r
688 bar = null;\r
689 });\r
690\r
691 it("should set the active item on the tab bar", function() {\r
692 tabPanel.setActiveTab(item2);\r
693 expect(bar.activeTab).toBe(item2.tab);\r
694 });\r
695\r
696 it("should not modify the tab bar item if the item cannot be found", function() {\r
697 tabPanel.setActiveTab(9);\r
698 expect(bar.activeTab).toBe(item1.tab);\r
699 });\r
700\r
701 it("should set the active item when adding a new item", function() {\r
702 tabPanel.setActiveTab({\r
703 itemId: 'item5'\r
704 });\r
705 expect(bar.activeTab).toBe(tabPanel.down('#item5').tab);\r
706 });\r
707\r
708 it("should not modify the tab bar item when beforetabchange returns false", function() {\r
709 tabPanel.on('beforetabchange', function() {\r
710 return false;\r
711 });\r
712 tabPanel.setActiveTab(item3);\r
713 expect(bar.activeTab).toBe(item1.tab);\r
714 });\r
715 });\r
716 });\r
717\r
718 describe("via the ui", function() {\r
719 function clickTab(item) {\r
720 runs(function() {\r
721 var target = item.tab.getEl().dom;\r
722 jasmine.fireMouseEvent(target, 'click');\r
723 });\r
724 \r
725 // Need to yield enough cycles to unwind event handlers\r
726 jasmine.waitAWhile();\r
727 }\r
728 \r
729 function expectActiveItem(want) {\r
730 runs(function() {\r
731 var have = tabPanel.getActiveTab();\r
732 \r
733 expect(have).toBe(want);\r
734 });\r
735 }\r
736 \r
737 var beforeSpy, spy;\r
738\r
739 beforeEach(function() {\r
740 beforeSpy = jasmine.createSpy().andReturn(true);\r
741 spy = jasmine.createSpy();\r
742 tabPanel.on('beforetabchange', beforeSpy);\r
743 tabPanel.on('tabchange', spy);\r
744 });\r
745\r
746 afterEach(function() {\r
747 beforeSpy = spy = null;\r
748 });\r
749\r
750 describe("mouse", function() {\r
751 describe("interaction", function() {\r
752 it("should set the active tab", function() {\r
753 clickTab(item2);\r
754 \r
755 waitForFocus(tab2);\r
756 \r
757 expectActiveItem(item2);\r
758 });\r
759 \r
760 it("should not set the active tab if the beforetabchange event returns false", function() {\r
761 runs(function() {\r
762 beforeSpy.andReturn(false);\r
763 });\r
764 \r
765 clickTab(item3);\r
766 \r
767 expectActiveItem(item1);\r
768 });\r
769\r
770 it("should not set the active tab if the tab is disabled", function() {\r
771 item2.setDisabled(true);\r
772 clickTab(item2);\r
773 expectActiveItem(item1);\r
774 });\r
775 });\r
776 \r
777 describe("focus handling", function() {\r
778 describe("during tab activate event", function() {\r
779 var textfield, tabFocusSpy, fieldFocusSpy;\r
780 \r
781 beforeEach(function() {\r
782 tabFocusSpy = jasmine.createSpy('tab focus');\r
783 fieldFocusSpy = jasmine.createSpy('textfield focus');\r
784 \r
785 textfield = item3.add({\r
786 xtype: 'textfield',\r
787 listeners: {\r
788 focus: fieldFocusSpy\r
789 }\r
790 });\r
791 \r
792 item3.on('activate', function() {\r
793 // Give IE enough time to repaint the textfield,\r
794 // otherwise it won't properly focus but *will*\r
795 // fire the focus event, which results in repeatable\r
796 // but very confusing failures.\r
797 // ***PURE UNDILUTED HATRED***\r
798 jasmine.waitAWhile();\r
799 \r
800 runs(function() {\r
801 tab3.getFocusEl().on('focus', tabFocusSpy);\r
802 textfield.focus();\r
803 });\r
804 });\r
805 });\r
806 \r
807 it("should not force focus back to the tab", function() {\r
808 clickTab(item3);\r
809 \r
810 waitForSpy(fieldFocusSpy);\r
811 \r
812 // Unwind the handlers that could potentially refocus\r
813 jasmine.waitAWhile();\r
814 \r
815 runs(function() {\r
816 expect(tabFocusSpy).not.toHaveBeenCalled();\r
817 });\r
818 });\r
819 });\r
820 });\r
821\r
822 describe("events", function() {\r
823 it("should fire no events if clicking on the active tab", function() {\r
824 clickTab(item1);\r
825 \r
826 waitForFocus(tab1);\r
827 \r
828 runs(function() {\r
829 expect(beforeSpy).not.toHaveBeenCalled();\r
830 expect(spy).not.toHaveBeenCalled();\r
831 });\r
832 });\r
833\r
834 it("should fire the beforetabchange event, passing the tab panel, new tab & old tab", function() {\r
835 clickTab(item2);\r
836 \r
837 waitForFocus(tab2);\r
838 \r
839 runs(function() {\r
840 expect(beforeSpy.callCount).toBe(1);\r
841 var args = beforeSpy.mostRecentCall.args;\r
842 expect(args[0]).toBe(tabPanel);\r
843 expect(args[1]).toBe(item2);\r
844 expect(args[2]).toBe(item1);\r
845 });\r
846 });\r
847\r
848 it("should fire the tabchange event, passing the tab panel, new tab & old tab", function() {\r
849 clickTab(item2);\r
850 \r
851 waitForFocus(tab2);\r
852 \r
853 runs(function() {\r
854 expect(spy.callCount).toBe(1);\r
855 var args = spy.mostRecentCall.args;\r
856 expect(args[0]).toBe(tabPanel);\r
857 expect(args[1]).toBe(item2);\r
858 expect(args[2]).toBe(item1);\r
859 });\r
860 });\r
861\r
862 it("should not fire the tabchange event if beforetabchange returns false", function() {\r
863 clickTab(item2);\r
864 \r
865 waitForFocus(tab2);\r
866 \r
867 runs(function() {\r
868 beforeSpy.andReturn(false);\r
869 spy = jasmine.createSpy();\r
870 });\r
871 \r
872 clickTab(item3);\r
873 \r
874 // Focus does change, but active tab does not\r
875 waitForFocus(tab3);\r
876 \r
877 runs(function() {\r
878 expect(spy).not.toHaveBeenCalled();\r
879 });\r
880 });\r
881 }); \r
882 });\r
883 \r
884 // Firefox and Safari on Mac will not focus <anchor> tags by default,\r
885 // and that will make some or all tests below to fail. Fix TBD.\r
886 var todoDescribe = (Ext.isMac && (Ext.isGecko || Ext.isSafari) ? xdescribe : describe);\r
887 \r
888 todoDescribe("keys", function() {\r
889 describe("arrows", function() {\r
890 it("should go right from 1 to 2", function() {\r
891 pressArrow(tab1, 'right');\r
892 \r
893 expectActiveItem(item2);\r
894 });\r
895 \r
896 it("should loop over right from 4 to 1", function() {\r
897 pressArrow(tab4, 'right');\r
898 \r
899 expectActiveItem(item1);\r
900 });\r
901 \r
902 it("should go left from 2 to 1", function() {\r
903 pressArrow(tab2, 'left');\r
904 \r
905 expectActiveItem(item1);\r
906 });\r
907 \r
908 it("should loop over left to 4 from 1", function() {\r
909 pressArrow(tab1, 'left');\r
910 \r
911 expectActiveItem(item4);\r
912 });\r
913 });\r
914 \r
915 describe("Space/Enter", function() {\r
916 it("should activate card on Space key", function() {\r
917 pressKey(tab2, 'space');\r
918 \r
919 expectActiveItem(item2);\r
920 });\r
921 \r
922 it("should activate card on Enter key", function() {\r
923 pressKey(tab3, 'enter');\r
924 \r
925 expectActiveItem(item3);\r
926 });\r
927 });\r
928 \r
929 describe("activation", function() {\r
930 describe("activateOnFocus == true (default)", function() {\r
931 beforeEach(function() {\r
932 pressArrow(tab1, 'right');\r
933 });\r
934 \r
935 it("should focus navigated-to tab", function() {\r
936 expectFocused(tab2);\r
937 });\r
938 \r
939 it("should activate navigated-to item", function() {\r
940 expectActiveItem(item2);\r
941 });\r
942 \r
943 it("should set active flag on navigated-to tab", function() {\r
944 runs(function() {\r
945 expect(tab1.active).toBeFalsy();\r
946 expect(tab2.active).toBe(true);\r
947 });\r
948 });\r
949 \r
950 it("should not attempt to activate a child that is not a Tab", function() {\r
951 var button;\r
952 \r
953 runs(function() {\r
954 button = new Ext.button.Button({\r
955 text: 'foo',\r
956 activate: jasmine.createSpy('activate')\r
957 });\r
958 \r
959 tabPanel.getTabBar().insert(2, button);\r
960 });\r
961 \r
962 pressArrow(tab2, 'right');\r
963 \r
964 // Need to defer waitForFocus until the button is rendered\r
965 // so there is some DOM to wait for :)\r
966 runs(function() {\r
967 waitForFocus(button);\r
968 });\r
969 \r
970 runs(function() {\r
971 expect(button.activate).not.toHaveBeenCalled();\r
972 });\r
973 });\r
974 });\r
975 \r
976 describe("activateOnFocus == false", function() {\r
977 beforeEach(function() {\r
978 runs(function() {\r
979 tabPanel.getTabBar().setActivateOnFocus(false);\r
980 });\r
981 \r
982 pressArrow(tab1, 'right');\r
983 });\r
984 \r
985 it("should focus navigated-to tab", function() {\r
986 expectFocused(tab2);\r
987 });\r
988 \r
989 it("should not activate navigated-to item", function() {\r
990 expectActiveItem(item1);\r
991 });\r
992 \r
993 it("should not set active flag on navigated-to tab", function() {\r
994 runs(function() {\r
995 expect(tab1.active).toBe(true);\r
996 expect(tab2.active).toBeFalsy();\r
997 });\r
998 });\r
999 });\r
1000 });\r
1001 \r
1002 describe("events", function() {\r
1003 // Focus by clicking before sending arrow key, so that\r
1004 // events fire on the actual change. We have to click instead of\r
1005 // just focusing because certain browsers (Firefox, I'm pointing at you!)\r
1006 // do not fire focusing events correctly, we have to emulate these\r
1007 // and things get messy real quick.\r
1008 beforeEach(function() {\r
1009 clickTab(item2);\r
1010 \r
1011 waitForFocus(tab2);\r
1012 });\r
1013 \r
1014 describe("beforetabchange", function() {\r
1015 beforeEach(function() {\r
1016 pressArrow(tab2, 'right');\r
1017 \r
1018 waitForFocus(tab3);\r
1019 });\r
1020 \r
1021 it("should fire the event", function() {\r
1022 runs(function() {\r
1023 // Extra call is when we're focusing the tab in beforeEach\r
1024 expect(beforeSpy.callCount).toBe(2);\r
1025 });\r
1026 });\r
1027 \r
1028 it("should pass the tab panel, new and old tab", function() {\r
1029 runs(function() {\r
1030 var args = beforeSpy.mostRecentCall.args;\r
1031 \r
1032 expect(args[0]).toBe(tabPanel);\r
1033 expect(args[1]).toBe(item3);\r
1034 expect(args[2]).toBe(item2);\r
1035 });\r
1036 });\r
1037 });\r
1038 \r
1039 describe("tabchange", function() {\r
1040 beforeEach(function() {\r
1041 pressArrow(tab2, 'left');\r
1042 \r
1043 waitForFocus(tab1);\r
1044 });\r
1045 \r
1046 it("should fire the event", function() {\r
1047 runs(function() {\r
1048 // Extra call is when we're focusing the tab in beforeEach\r
1049 expect(spy.callCount).toBe(2);\r
1050 });\r
1051 });\r
1052 \r
1053 it("should pass the tab panel, new and old tab", function() {\r
1054 runs(function() {\r
1055 var args = spy.mostRecentCall.args;\r
1056 \r
1057 expect(args[0]).toBe(tabPanel);\r
1058 expect(args[1]).toBe(item1);\r
1059 expect(args[2]).toBe(item2);\r
1060 });\r
1061 });\r
1062 });\r
1063 \r
1064 describe("canceling beforetabchange", function() {\r
1065 beforeEach(function() {\r
1066 beforeSpy.andReturn(false);\r
1067 \r
1068 // It was called when we focused tab2\r
1069 spy = jasmine.createSpy();\r
1070 \r
1071 pressArrow(tab2, 'right');\r
1072 \r
1073 // Focus should change\r
1074 waitForFocus(tab3);\r
1075 });\r
1076 \r
1077 it("should move focus to tab3", function() {\r
1078 expectFocused(tab3);\r
1079 });\r
1080 \r
1081 it("should not fire tabchange event", function() {\r
1082 expect(spy).not.toHaveBeenCalled();\r
1083 });\r
1084 });\r
1085 \r
1086 describe("focusing non-Tab children", function() {\r
1087 var button, beforeCount, changeCount;\r
1088 \r
1089 beforeEach(function() {\r
1090 runs(function() {\r
1091 button = new Ext.button.Button({\r
1092 text: 'foo'\r
1093 });\r
1094 \r
1095 tabPanel.getTabBar().insert(2, button);\r
1096 \r
1097 // Both spies are called when we change tabs above\r
1098 beforeCount = beforeSpy.callCount;\r
1099 changeCount = spy.callCount;\r
1100 });\r
1101\r
1102 pressArrow(tab2, 'right');\r
1103 \r
1104 runs(function() {\r
1105 waitForFocus(button);\r
1106 });\r
1107 });\r
1108 \r
1109 it("should not fire beforetabchange event", function() {\r
1110 expect(beforeSpy.callCount).toBe(beforeCount);\r
1111 });\r
1112 \r
1113 it("should not fire tabchange event", function() {\r
1114 expect(spy.callCount).toBe(changeCount);\r
1115 });\r
1116 });\r
1117 });\r
1118 });\r
1119 });\r
1120 });\r
1121 \r
1122 describe("removing child components", function() {\r
1123 it("should remove the corresponding tab from the tabBar", function() {\r
1124 createTabPanelWithTabs(2);\r
1125 \r
1126 var secondPanel = tabPanel.items.last(),\r
1127 tabBar = tabPanel.getTabBar(),\r
1128 oldCount = tabBar.items.length;\r
1129 \r
1130 tabPanel.remove(secondPanel);\r
1131 \r
1132 expect(tabBar.items.length).toEqual(oldCount - 1);\r
1133 });\r
1134 \r
1135 describe("if the removed child is the currently active tab", function() {\r
1136 var firstItem, secondItem, thirdItem;\r
1137\r
1138 describe("and there is at least one tab after it", function() {\r
1139 beforeEach(function() {\r
1140 createTabPanelWithTabs(3, {renderTo: document.body, activeTab: 1});\r
1141 firstItem = tabPanel.items.first();\r
1142 secondItem = tabPanel.items.getAt(1);\r
1143 thirdItem = tabPanel.items.last();\r
1144 });\r
1145 \r
1146 it("should activate the next tab", function() {\r
1147 // second is currently active\r
1148 tabPanel.remove(secondItem);\r
1149 expect(tabPanel.getActiveTab().title).toEqual(thirdItem.title);\r
1150 });\r
1151 });\r
1152 \r
1153 describe("and there is no tab before it but at least one after it", function() {\r
1154 beforeEach(function() {\r
1155 createTabPanelWithTabs(2, {renderTo: document.body, activeTab: 0});\r
1156 firstItem = tabPanel.items.items[0];\r
1157 secondItem = tabPanel.items.items[1];\r
1158 });\r
1159 \r
1160 it("should activate the next tab", function() {\r
1161 // first is currently active\r
1162 tabPanel.remove(firstItem);\r
1163 expect(tabPanel.getActiveTab().title).toEqual(secondItem.title);\r
1164 });\r
1165 });\r
1166 \r
1167 describe("and there are no other tabs", function() {\r
1168 beforeEach(function() {\r
1169 createTabPanelWithTabs(1);\r
1170 firstItem = tabPanel.items.first();\r
1171 });\r
1172 \r
1173 it("should not activate any other tabs", function() {\r
1174 tabPanel.remove(firstItem);\r
1175 expect(tabPanel.getActiveTab()).toBeUndefined();\r
1176 });\r
1177 });\r
1178 });\r
1179 });\r
1180 \r
1181 describe("AutoSizing", function() {\r
1182 beforeEach(function() {\r
1183 createTabPanel({\r
1184 width: 600,\r
1185 items: [{\r
1186 title: '200 hi',\r
1187 height: 200\r
1188 }, {\r
1189 title: '400 hi',\r
1190 height: 400\r
1191 }],\r
1192 renderTo: document.body\r
1193 });\r
1194 });\r
1195\r
1196 it("should activate the first tab, and size to accommodate it", function() {\r
1197 expect(tabPanel.body.getViewSize().height).toBe(200);\r
1198 });\r
1199 it("should activate the second tab, and size to accommodate it", function() {\r
1200 tabPanel.setActiveTab(1);\r
1201 expect(tabPanel.body.getViewSize().height).toBe(400);\r
1202 });\r
1203 });\r
1204\r
1205 xdescribe("TabPanel's minTabWidth/maxTabWidth", function() {\r
1206 it('Should create a single tab with width of 200', function() {\r
1207 createTabPanel({\r
1208 renderTo: document.body,\r
1209 minTabWidth: 200,\r
1210 items: {\r
1211 title: 'Short'\r
1212 }\r
1213 });\r
1214 expect(tabPanel.down('tab').getWidth()).toBe(200);\r
1215 });\r
1216 it('Should create a single tab with width of 20', function() {\r
1217 createTabPanel({\r
1218 renderTo: document.body,\r
1219 maxTabWidth: 20,\r
1220 items: {\r
1221 title: 'A very long title, but the tab must only be 20 wide'\r
1222 }\r
1223 });\r
1224 expect(tabPanel.down('tab').getWidth()).toBe(20);\r
1225 });\r
1226 });\r
1227\r
1228 // Tests in this suite are about non-visual things, and rendering is disabled\r
1229 // to avoid odd layout failures in IE9m\r
1230 describe("ui", function() {\r
1231 it("should use the TabPanel's ui as the default UI for the Tab Bar and Tab", function() {\r
1232 createTabPanel({\r
1233 renderTo: undefined,\r
1234 ui: 'foo',\r
1235 items: [{ title: 'A' }]\r
1236 });\r
1237\r
1238 expect(tabPanel.tabBar.ui).toBe('foo');\r
1239 expect(tabPanel.items.getAt(0).tab.ui).toBe('foo');\r
1240 });\r
1241\r
1242 it("should use the Tab Bar's ui as the default UI for Tabs", function() {\r
1243 createTabPanel({\r
1244 renderTo: undefined,\r
1245 ui: 'foo',\r
1246 tabBar: {\r
1247 ui: 'bar'\r
1248 },\r
1249 items: [{ title: 'A' }]\r
1250 });\r
1251\r
1252 expect(tabPanel.tabBar.ui).toBe('bar');\r
1253 expect(tabPanel.items.getAt(0).tab.ui).toBe('bar');\r
1254 });\r
1255\r
1256 it("should allow the tab to override the default UI", function() {\r
1257 createTabPanel({\r
1258 renderTo: undefined,\r
1259 ui: 'foo',\r
1260 tabBar: {\r
1261 ui: 'bar'\r
1262 },\r
1263 items: [{\r
1264 title: 'A',\r
1265 tabConfig: {\r
1266 ui: 'baz'\r
1267 }\r
1268 }]\r
1269 });\r
1270\r
1271 expect(tabPanel.tabBar.ui).toBe('bar');\r
1272 expect(tabPanel.items.getAt(0).tab.ui).toBe('baz');\r
1273 });\r
1274 });\r
1275\r
1276 describe("bind", function() {\r
1277 it("should be able to bind the tab title when the view model is on the tab panel", function() {\r
1278 createTabPanel({\r
1279 renderTo: Ext.getBody(),\r
1280 viewModel: {\r
1281 data: {\r
1282 tab1: 'Foo',\r
1283 tab2: 'Bar'\r
1284 }\r
1285 },\r
1286 items: [{\r
1287 bind: '{tab1}'\r
1288 }, {\r
1289 bind: '{tab2}'\r
1290 }]\r
1291 });\r
1292 tabPanel.getViewModel().notify();\r
1293 var bar = tabPanel.getTabBar();\r
1294 expect(bar.items.first().getText()).toBe('Foo');\r
1295 expect(bar.items.last().getText()).toBe('Bar');\r
1296 });\r
1297\r
1298 it("should be able to bind the tab title when the view model is on the tab item", function() {\r
1299 createTabPanel({\r
1300 renderTo: Ext.getBody(),\r
1301 items: [{\r
1302 bind: '{title}',\r
1303 viewModel: {\r
1304 data: {title: 'Foo'}\r
1305 }\r
1306 }, {\r
1307 bind: '{title}',\r
1308 viewModel: {\r
1309 data: {title: 'Bar'}\r
1310 }\r
1311 }]\r
1312 });\r
1313 var bar = tabPanel.getTabBar();\r
1314 tabPanel.items.first().getViewModel().notify();\r
1315 tabPanel.items.last().getViewModel().notify();\r
1316 expect(bar.items.first().getText()).toBe('Foo');\r
1317 expect(bar.items.last().getText()).toBe('Bar');\r
1318 });\r
1319\r
1320 it("should not instance a view model inside an inactive tab when binding the title to a view model on the tab", function() {\r
1321 createTabPanel({\r
1322 renderTo: Ext.getBody(),\r
1323 items: [{\r
1324 title: 'Foo'\r
1325 }, {\r
1326 bind: '{title}',\r
1327 viewModel: {\r
1328 data: {title: 'Bar'}\r
1329 },\r
1330 items: {\r
1331 xtype: 'component',\r
1332 viewModel: {\r
1333 data: {}\r
1334 }\r
1335 }\r
1336 }]\r
1337 });\r
1338 var item = tabPanel.items.last();\r
1339 item.getViewModel().notify();\r
1340 expect(item.items.first().getConfig('viewModel', true).isViewModel).not.toBe(true);\r
1341 });\r
1342 });\r
1343\r
1344 describe("removeAll", function() {\r
1345 it("should not activate any items", function() {\r
1346 var spy = jasmine.createSpy();\r
1347 tabPanel = new Ext.tab.Panel({\r
1348 renderTo: Ext.getBody(),\r
1349 items: [{\r
1350 title: 'Item 1'\r
1351 }, {\r
1352 title: 'Item 2',\r
1353 listeners: {\r
1354 activate: spy\r
1355 }\r
1356 }, {\r
1357 title: 'Item 3',\r
1358 listeners: {\r
1359 activate: spy\r
1360 }\r
1361 }]\r
1362 });\r
1363 tabPanel.removeAll();\r
1364 expect(spy).not.toHaveBeenCalled();\r
1365 });\r
1366\r
1367 it("should not render any items during destroy", function() {\r
1368 var spy = jasmine.createSpy();\r
1369 tabPanel = new Ext.tab.Panel({\r
1370 renderTo: Ext.getBody(),\r
1371 items: [{\r
1372 title: 'Item 1'\r
1373 }, {\r
1374 title: 'Item 2',\r
1375 listeners: {\r
1376 afterrender: spy\r
1377 }\r
1378 }, {\r
1379 title: 'Item 3',\r
1380 listeners: {\r
1381 afterrender: spy\r
1382 }\r
1383 }]\r
1384 });\r
1385 tabPanel.removeAll();\r
1386 expect(spy).not.toHaveBeenCalled();\r
1387 });\r
1388 });\r
1389 \r
1390 describe("cleanup", function() {\r
1391 it("should leave no orphans", function() {\r
1392 var count = Ext.ComponentManager.getCount();\r
1393 tabPanel = new Ext.tab.Panel({\r
1394 renderTo: Ext.getBody(),\r
1395 items: [{\r
1396 title: 'Item 1',\r
1397 closable: true\r
1398 }, {\r
1399 title: 'Item 2',\r
1400 closable: true\r
1401 }, {\r
1402 title: 'Item 3',\r
1403 closable: true\r
1404 }]\r
1405 });\r
1406 tabPanel.destroy();\r
1407 expect(Ext.ComponentManager.getCount()).toBe(count);\r
1408 }); \r
1409\r
1410 it("should not activate any items during destroy", function() {\r
1411 var spy = jasmine.createSpy();\r
1412 tabPanel = new Ext.tab.Panel({\r
1413 renderTo: Ext.getBody(),\r
1414 items: [{\r
1415 title: 'Item 1'\r
1416 }, {\r
1417 title: 'Item 2',\r
1418 listeners: {\r
1419 activate: spy\r
1420 }\r
1421 }, {\r
1422 title: 'Item 3',\r
1423 listeners: {\r
1424 activate: spy\r
1425 }\r
1426 }]\r
1427 });\r
1428 tabPanel.destroy();\r
1429 expect(spy).not.toHaveBeenCalled();\r
1430 });\r
1431\r
1432 it("should not render any items during destroy", function() {\r
1433 var spy = jasmine.createSpy();\r
1434 tabPanel = new Ext.tab.Panel({\r
1435 renderTo: Ext.getBody(),\r
1436 items: [{\r
1437 title: 'Item 1'\r
1438 }, {\r
1439 title: 'Item 2',\r
1440 listeners: {\r
1441 afterrender: spy\r
1442 }\r
1443 }, {\r
1444 title: 'Item 3',\r
1445 listeners: {\r
1446 afterrender: spy\r
1447 }\r
1448 }]\r
1449 });\r
1450 tabPanel.destroy();\r
1451 expect(spy).not.toHaveBeenCalled();\r
1452 });\r
1453 });\r
1454\r
1455 describe('Loader', function () {\r
1456 var panel;\r
1457\r
1458 function createPanel(cfg) {\r
1459 panel = createTabPanel(Ext.apply({\r
1460 renderTo: document.body,\r
1461 deferredRender: false,\r
1462 items: [{\r
1463 title: 'Tab 1'\r
1464 }, {\r
1465 title: 'Tab 2'\r
1466 }],\r
1467 loader: {\r
1468 url: 'url',\r
1469 renderer: 'component'\r
1470 }\r
1471 }, cfg || {}));\r
1472 }\r
1473\r
1474 function mockComplete(responseText, status) {\r
1475 Ext.Ajax.mockComplete({\r
1476 status: status || 200,\r
1477 responseText: responseText || 'response'\r
1478 });\r
1479 }\r
1480\r
1481 beforeEach(function () {\r
1482 MockAjaxManager.addMethods();\r
1483 });\r
1484\r
1485 afterEach(function () {\r
1486 panel.destroy();\r
1487 panel = null;\r
1488 MockAjaxManager.removeMethods();\r
1489 });\r
1490\r
1491 it('should add to the number of tabs', function () {\r
1492 createPanel();\r
1493 tabPanel.loader.load();\r
1494 mockComplete("[{title: 'Tab 3'}, {title: 'Tab 4'}]");\r
1495 expect(tabPanel.tabBar.items.length).toEqual(4);\r
1496 });\r
1497\r
1498 describe('setActiveTab', function () {\r
1499 describe('pre-existing tabs', function () {\r
1500 it('should not call setActiveTab', function () {\r
1501 createPanel();\r
1502 spyOn(tabPanel, 'setActiveTab');\r
1503\r
1504 tabPanel.loader.load();\r
1505 mockComplete("[{title: 'Tab 3'}, {title: 'Tab 4'}]");\r
1506\r
1507 expect(tabPanel.setActiveTab).wasNotCalled();\r
1508 });\r
1509\r
1510 it('should not call setActiveTab when activeItem is null', function () {\r
1511 createPanel({\r
1512 activeTab: null\r
1513 });\r
1514 spyOn(tabPanel, 'setActiveTab');\r
1515\r
1516 tabPanel.loader.load();\r
1517 mockComplete("[{title: 'Tab 3'}, {title: 'Tab 4'}]");\r
1518\r
1519 expect(tabPanel.setActiveTab).wasNotCalled();\r
1520 });\r
1521 });\r
1522\r
1523 describe('no pre-existing tabs', function () {\r
1524 it('should call setActiveTab', function () {\r
1525 createPanel({\r
1526 items: null\r
1527 });\r
1528\r
1529 spyOn(tabPanel, 'setActiveTab');\r
1530\r
1531 tabPanel.loader.load();\r
1532 mockComplete("[{title: 'Tab 1'}, {title: 'Tab 2'}]");\r
1533\r
1534 expect(tabPanel.tabBar.items.length).toEqual(2);\r
1535 expect(tabPanel.setActiveTab).toHaveBeenCalled();\r
1536 });\r
1537\r
1538 it('should not call setActiveTab when activeItem is null', function () {\r
1539 createPanel({\r
1540 activeTab: null,\r
1541 items: null\r
1542 });\r
1543 spyOn(tabPanel, 'setActiveTab');\r
1544\r
1545 tabPanel.loader.load();\r
1546 mockComplete("[{title: 'Tab 3'}, {title: 'Tab 4'}]");\r
1547\r
1548 expect(tabPanel.setActiveTab).wasNotCalled();\r
1549 });\r
1550 });\r
1551\r
1552 describe('during a pending load', function () {\r
1553 // See EXTJS-16054.\r
1554 beforeEach(function () {\r
1555 createPanel({\r
1556 items: null\r
1557 });\r
1558\r
1559 tabPanel.setActiveTab(1);\r
1560 });\r
1561\r
1562 it('should not set the activeTab as null', function () {\r
1563 expect(tabPanel.getActiveTab()).not.toBeNull();\r
1564\r
1565 tabPanel.loader.load();\r
1566 mockComplete("[{title: 'Tab 1'}, {title: 'Tab 2'}]");\r
1567 });\r
1568\r
1569 it('should set the activeTab as undefined', function () {\r
1570 expect(tabPanel.getActiveTab()).toBeUndefined();\r
1571\r
1572 tabPanel.loader.load();\r
1573 mockComplete("[{title: 'Tab 1'}, {title: 'Tab 2'}]");\r
1574 });\r
1575\r
1576 it('should set a default tab as active when load returns', function () {\r
1577 tabPanel.loader.load();\r
1578 mockComplete("[{title: 'Tab 1'}, {title: 'Tab 2'}]");\r
1579\r
1580 expect(tabPanel.getActiveTab()).toBeDefined();\r
1581 });\r
1582 });\r
1583 });\r
1584\r
1585 describe('loading new tabs', function () {\r
1586 it('should not set an active item when activeItem is null (pre-existing tabs)', function () {\r
1587 createPanel({\r
1588 activeTab: null\r
1589 });\r
1590\r
1591 tabPanel.loader.load();\r
1592 mockComplete("[{title: 'Tab 3'}, {title: 'Tab 4'}]");\r
1593\r
1594 //expect(tabPanel.layout.getActiveItem()).toBe(null);\r
1595 expect(tabPanel.layout.getActiveItem() === null).toBe(true);\r
1596 });\r
1597\r
1598 it('should not set an active item when activeItem is null (no pre-existing tabs)', function () {\r
1599 createPanel({\r
1600 activeTab: null,\r
1601 items: null\r
1602 });\r
1603\r
1604 tabPanel.loader.load();\r
1605 mockComplete("[{title: 'Tab 1'}, {title: 'Tab 2'}]");\r
1606\r
1607 expect(tabPanel.layout.getActiveItem() === null).toBe(true);\r
1608 });\r
1609 });\r
1610\r
1611 describe('tabchange event', function () {\r
1612 var called = false;\r
1613\r
1614 afterEach(function () {\r
1615 called = false;\r
1616 });\r
1617\r
1618 describe('pre-existing tabs', function () {\r
1619 it('should not fire', function () {\r
1620 createPanel();\r
1621\r
1622 tabPanel.on('tabchange', function () {\r
1623 called = true;\r
1624 }, this);\r
1625\r
1626 tabPanel.loader.load();\r
1627 mockComplete("[{title: 'Tab 3'}, {title: 'Tab 4'}]");\r
1628\r
1629 expect(called).toBe(false);\r
1630 });\r
1631\r
1632 it('should not fire when activeItem is null', function () {\r
1633 createPanel({\r
1634 activeTab: null\r
1635 });\r
1636\r
1637 tabPanel.on('tabchange', function () {\r
1638 called = true;\r
1639 }, this);\r
1640\r
1641 tabPanel.loader.load();\r
1642 mockComplete("[{title: 'Tab 3'}, {title: 'Tab 4'}]");\r
1643\r
1644 expect(called).toBe(false);\r
1645 });\r
1646 });\r
1647\r
1648 describe('no pre-existing tabs', function () {\r
1649 it('should fire', function () {\r
1650 createPanel({\r
1651 items: null\r
1652 });\r
1653\r
1654 tabPanel.on('tabchange', function () {\r
1655 called = true;\r
1656 }, this);\r
1657\r
1658 tabPanel.loader.load();\r
1659 mockComplete("[{title: 'Tab 1'}, {title: 'Tab 2'}]");\r
1660\r
1661 expect(tabPanel.tabBar.items.length).toEqual(2);\r
1662 expect(called).toBe(true);\r
1663 });\r
1664\r
1665 it('should not fire when activeItem is null', function () {\r
1666 createPanel({\r
1667 activeTab: null,\r
1668 items: null\r
1669 });\r
1670\r
1671 tabPanel.on('tabchange', function () {\r
1672 called = true;\r
1673 }, this);\r
1674\r
1675 tabPanel.loader.load();\r
1676 mockComplete("[{title: 'Tab 3'}, {title: 'Tab 4'}]");\r
1677\r
1678 expect(called).toBe(false);\r
1679 });\r
1680 });\r
1681 });\r
1682 });\r
1683\r
1684 describe("tabRotation", function() {\r
1685 it("should not override the rotation config of indiviual tabs", function() {\r
1686 createTabPanel({\r
1687 tabRotation: 2,\r
1688 items: [{\r
1689 tabConfig: {\r
1690 rotation: 0\r
1691 }\r
1692 }]\r
1693 });\r
1694\r
1695 expect(tabPanel.tabBar.items.getAt(0).rotation).toBe(0);\r
1696 });\r
1697\r
1698 it("should not override the rotation config of indiviual tabs, when tabPosition is configured", function() {\r
1699 createTabPanel({\r
1700 tabPosition: 'right',\r
1701 items: [{\r
1702 tabConfig: {\r
1703 rotation: 0\r
1704 }\r
1705 }]\r
1706 });\r
1707\r
1708 expect(tabPanel.tabBar.items.getAt(0).rotation).toBe(0);\r
1709 });\r
1710\r
1711 it("should allow rotation to be configured on the tabBar", function() {\r
1712 createTabPanelWithTabs(1, {\r
1713 tabBar: {\r
1714 tabRotation: 2\r
1715 }\r
1716 });\r
1717 expect(tabPanel.tabBar.items.getAt(0).rotation).toBe(2);\r
1718 });\r
1719\r
1720 it("should pass configured tabRotation on to the tabs", function() {\r
1721 createTabPanelWithTabs(1, {\r
1722 tabRotation: 2\r
1723 });\r
1724 expect(tabPanel.tabBar.items.getAt(0).rotation).toBe(2);\r
1725 });\r
1726\r
1727 describe("default behavior", function() {\r
1728 it("should not have rotation classes for tabPosition:top", function() {\r
1729 createTabPanelWithTabs(1);\r
1730 expect(tabPanel.tabBar.items.getAt(0).el).not.toHaveCls('x-tab-rotate-left');\r
1731 expect(tabPanel.tabBar.items.getAt(0).el).not.toHaveCls('x-tab-rotate-right');\r
1732 });\r
1733\r
1734 it("should default to 0 for tabPosition:bottom", function() {\r
1735 createTabPanelWithTabs(1, {\r
1736 tabPosition: 'bottom'\r
1737 });\r
1738\r
1739 expect(tabPanel.tabBar.items.getAt(0).el).not.toHaveCls('x-tab-rotate-left');\r
1740 expect(tabPanel.tabBar.items.getAt(0).el).not.toHaveCls('x-tab-rotate-right');\r
1741 });\r
1742\r
1743 it("should have right rotation cls for tabPosition:right", function() {\r
1744 createTabPanelWithTabs(1, {\r
1745 tabPosition: 'right'\r
1746 });\r
1747\r
1748 expect(tabPanel.tabBar.items.getAt(0).el).not.toHaveCls('x-tab-rotate-left');\r
1749 expect(tabPanel.tabBar.items.getAt(0).el).toHaveCls('x-tab-rotate-right');\r
1750 });\r
1751\r
1752 it("should have left rotation cls for tabPosition:left", function() {\r
1753 createTabPanelWithTabs(1, {\r
1754 tabPosition: 'left'\r
1755 });\r
1756\r
1757 expect(tabPanel.tabBar.items.getAt(0).el).toHaveCls('x-tab-rotate-left');\r
1758 expect(tabPanel.tabBar.items.getAt(0).el).not.toHaveCls('x-tab-rotate-right');\r
1759 });\r
1760 });\r
1761 });\r
1762\r
1763 describe("tabBarHeaderPosition", function() {\r
1764 it("should render the tabBar as a docked item if tabBarHeaderPosition is unspecified", function() {\r
1765 createTabPanelWithTabs(1);\r
1766 expect(tabPanel.getDockedItems()[0]).toBe(tabPanel.tabBar);\r
1767 });\r
1768\r
1769 it("should render the tabBar as a header item if tabBarHeaderPosition is specified", function() {\r
1770 createTabPanelWithTabs(1, {\r
1771 tabBarHeaderPosition: 0\r
1772 });\r
1773 expect(tabPanel.getDockedItems().length).toBe(1);\r
1774 expect(tabPanel.getDockedItems()[0]).toBe(tabPanel.header);\r
1775 expect(tabPanel.tabBar.ownerCt).toBe(tabPanel.header);\r
1776 });\r
1777\r
1778 it("should render the tabBar before the title", function() {\r
1779 createTabPanelWithTabs(1, {\r
1780 ariaRole: 'tabpanel',\r
1781 title: 'Foo',\r
1782 tabBarHeaderPosition: 0\r
1783 });\r
1784 expect(tabPanel.getDockedItems().length).toBe(1);\r
1785 expect(tabPanel.getDockedItems()[0]).toBe(tabPanel.header);\r
1786 expect(tabPanel.tabBar.ownerCt).toBe(tabPanel.header);\r
1787 expect(tabPanel.header.items.getAt(0)).toBe(tabPanel.tabBar);\r
1788 expect(tabPanel.header.items.getAt(1)).toBe(tabPanel.header.getTitle());\r
1789 });\r
1790\r
1791 it("should render the tabBar after the title", function() {\r
1792 createTabPanelWithTabs(1, {\r
1793 ariaRole: 'tabpanel',\r
1794 title: 'Foo',\r
1795 tabBarHeaderPosition: 1\r
1796 });\r
1797 expect(tabPanel.getDockedItems().length).toBe(1);\r
1798 expect(tabPanel.getDockedItems()[0]).toBe(tabPanel.header);\r
1799 expect(tabPanel.tabBar.ownerCt).toBe(tabPanel.header);\r
1800 expect(tabPanel.header.items.getAt(0)).toBe(tabPanel.header.getTitle());\r
1801 expect(tabPanel.header.items.getAt(1)).toBe(tabPanel.tabBar);\r
1802 });\r
1803\r
1804 it("should default the tabBar's 'dock' config to 'top' when inside a top header", function() {\r
1805 createTabPanelWithTabs(1, {\r
1806 tabBarHeaderPosition: 0\r
1807 });\r
1808 expect(tabPanel.tabBar.dock).toBe('top');\r
1809 });\r
1810\r
1811 it("should default the tabBar's 'dock' config to 'right' when inside a right header", function() {\r
1812 createTabPanelWithTabs(1, {\r
1813 headerPosition: 'right',\r
1814 tabBarHeaderPosition: 0\r
1815 });\r
1816 expect(tabPanel.tabBar.dock).toBe('right');\r
1817 });\r
1818\r
1819 it("should default the tabBar's 'dock' config to 'bottom' when inside a bottom header", function() {\r
1820 createTabPanelWithTabs(1, {\r
1821 headerPosition: 'bottom',\r
1822 tabBarHeaderPosition: 0\r
1823 });\r
1824 expect(tabPanel.tabBar.dock).toBe('bottom');\r
1825 });\r
1826\r
1827 it("should default the tabBar's 'dock' config to 'left' when inside a left header", function() {\r
1828 createTabPanelWithTabs(1, {\r
1829 headerPosition: 'left',\r
1830 tabBarHeaderPosition: 0\r
1831 });\r
1832 expect(tabPanel.tabBar.dock).toBe('left');\r
1833 });\r
1834\r
1835 it("should render the tabBar after any existing header items", function() {\r
1836 createTabPanelWithTabs(1, {\r
1837 header: {\r
1838 items: [{\r
1839 xtype: 'button',\r
1840 text: 'hi'\r
1841 }]\r
1842 },\r
1843 tabBarHeaderPosition: 0\r
1844 });\r
1845\r
1846 expect(tabPanel.header.items.getAt(0) instanceof Ext.button.Button).toBe(true);\r
1847 expect(tabPanel.header.items.getAt(1)).toBe(tabPanel.tabBar);\r
1848 });\r
1849\r
1850 it("should not mutate the header config", function() {\r
1851 var headerCfg = {\r
1852 title: 'Foo',\r
1853 items: [{\r
1854 xtype: 'button',\r
1855 text: 'hi'\r
1856 }]\r
1857 };\r
1858 createTabPanelWithTabs(1, {\r
1859 header: headerCfg,\r
1860 tabBarHeaderPosition: 1\r
1861 });\r
1862 expect(headerCfg.items.length).toBe(1);\r
1863 expect(tabPanel.header.items.getCount()).toBe(3);\r
1864 });\r
1865 });\r
1866\r
1867 describe("tabPosition", function() {\r
1868 it("should dock the tabBar to the top when tabPosition is 'top'", function() {\r
1869 createTabPanelWithTabs(1);\r
1870 expect(tabPanel.tabBar.dock).toBe('top');\r
1871 });\r
1872\r
1873 it("should dock the tabBar to the right when tabPosition is 'right'", function() {\r
1874 createTabPanelWithTabs(1, {\r
1875 tabPosition: 'right'\r
1876 });\r
1877 expect(tabPanel.tabBar.dock).toBe('right');\r
1878 });\r
1879\r
1880 it("should dock the tabBar to the bottom when tabPosition is 'bottom'", function() {\r
1881 createTabPanelWithTabs(1, {\r
1882 tabPosition: 'bottom'\r
1883 });\r
1884 expect(tabPanel.tabBar.dock).toBe('bottom');\r
1885 });\r
1886\r
1887 it("should dock the tabBar to the left when tabPosition is 'left'", function() {\r
1888 createTabPanelWithTabs(1, {\r
1889 tabPosition: 'left'\r
1890 });\r
1891 expect(tabPanel.tabBar.dock).toBe('left');\r
1892 });\r
1893\r
1894 it("should ignore tabPosition when tabBarHeaderPosition is specified", function() {\r
1895 createTabPanelWithTabs(1, {\r
1896 tabPosition: 'left',\r
1897 headerPosition: 'bottom',\r
1898 tabBarHeaderPosition: 0\r
1899 });\r
1900\r
1901 expect(tabPanel.tabBar.dock).toBe('bottom');\r
1902 });\r
1903\r
1904 it("should set tabPosition after rendering", function() {\r
1905 createTabPanelWithTabs(1);\r
1906\r
1907 tabPanel.setTabPosition('left');\r
1908 expect(tabPanel.tabBar.dock).toBe('left');\r
1909 });\r
1910\r
1911 it("should not allow setting of tabPosition after rendering if tabBarHeaderPosition was specified", function() {\r
1912 createTabPanelWithTabs(1, {\r
1913 headerPosition: 'bottom',\r
1914 tabBarHeaderPosition: 0\r
1915 });\r
1916\r
1917 tabPanel.setTabPosition('left');\r
1918 expect(tabPanel.tabBar.dock).toBe('bottom');\r
1919 });\r
1920\r
1921\r
1922 });\r
1923 \r
1924 describe("ARIA", function() {\r
1925 var expectAria = jasmine.expectAriaAttr,\r
1926 expectNoAria = jasmine.expectNoAriaAttr,\r
1927 tab1, tab2, card1, card2;\r
1928 \r
1929 beforeEach(function() {\r
1930 createTabPanelWithTabs(2);\r
1931 \r
1932 card1 = tabPanel.items.getAt(0);\r
1933 card2 = tabPanel.items.getAt(1);\r
1934 \r
1935 tab1 = card1.tab;\r
1936 tab2 = card2.tab;\r
1937 });\r
1938 \r
1939 afterEach(function() {\r
1940 tab1 = tab2 = card1 = card2 = null;\r
1941 });\r
1942 \r
1943 describe("attributes", function() {\r
1944 it("should have tab role on the tab", function() {\r
1945 expectAria(tab1, 'role', 'tab');\r
1946 });\r
1947 \r
1948 it("should have tabpanel role on the card", function() {\r
1949 expectAria(card1, 'role', 'tabpanel');\r
1950 });\r
1951 \r
1952 it("should have aria-selected='true' on tab1", function() {\r
1953 expectAria(tab1, 'aria-selected', 'true');\r
1954 });\r
1955 \r
1956 it("should have aria-selected='false' on tab2", function() {\r
1957 expectAria(tab2, 'aria-selected', 'false');\r
1958 });\r
1959 \r
1960 it("should have aria-labelledby on card1", function() {\r
1961 expectAria(card1, 'aria-labelledby', tab1.id);\r
1962 });\r
1963 \r
1964 it("should not have aria-label on card1", function() {\r
1965 expectNoAria(card1, 'aria-label');\r
1966 });\r
1967 \r
1968 it("should have aria-expanded='true' on card1", function() {\r
1969 expectAria(card1, 'aria-expanded', 'true');\r
1970 });\r
1971 \r
1972 it("should have aria-hidden='false' on card1", function() {\r
1973 expectAria(card1, 'aria-hidden', 'false');\r
1974 });\r
1975 \r
1976 describe("dynamically added panel", function() {\r
1977 var tab3, card3;\r
1978 \r
1979 beforeEach(function() {\r
1980 card3 = tabPanel.add(new Ext.panel.Panel({\r
1981 title: '<span style="background-color: red">foo</span>',\r
1982 html: 'blerg'\r
1983 }));\r
1984 \r
1985 tab3 = card3.tab;\r
1986 \r
1987 // This is to render the tab child\r
1988 tabPanel.setActiveTab(2);\r
1989 });\r
1990 \r
1991 afterEach(function() {\r
1992 tab3 = card3 = null;\r
1993 });\r
1994 \r
1995 it("should have correct aria-labelledby on card1", function() {\r
1996 expectAria(card3, 'aria-labelledby', tab3.id);\r
1997 });\r
1998 \r
1999 it("should not have aria-label on card1", function() {\r
2000 expectNoAria(card3, 'aria-label');\r
2001 });\r
2002 });\r
2003 \r
2004 describe("dynamically moved panel", function() {\r
2005 var tabPanel2, oldTab1Id;\r
2006 \r
2007 beforeEach(function() {\r
2008 tabPanel2 = new Ext.tab.Panel({\r
2009 renderTo: Ext.getBody()\r
2010 });\r
2011 \r
2012 oldTab1Id = tab1.id;\r
2013 \r
2014 tabPanel.remove(card1, false);\r
2015 tabPanel2.add(card1);\r
2016 \r
2017 tab1 = card1.tab;\r
2018 });\r
2019 \r
2020 afterEach(function() {\r
2021 tabPanel2.destroy();\r
2022 tabPanel2 = oldTab1Id = null;\r
2023 });\r
2024 \r
2025 it("should have new tab id on card1", function() {\r
2026 expect(tab1.id).not.toBe(oldTab1Id);\r
2027 });\r
2028 \r
2029 it("should have correct aria-labelledby on card1", function() {\r
2030 expectAria(card1, 'aria-labelledby', tab1.id);\r
2031 });\r
2032 \r
2033 it("should not have aria-label on card1", function() {\r
2034 expectNoAria(card1, 'aria-label');\r
2035 });\r
2036 });\r
2037 });\r
2038 \r
2039 describe("tab switching", function() {\r
2040 beforeEach(function() {\r
2041 tabPanel.setActiveTab(1);\r
2042 });\r
2043 \r
2044 describe("aria-selected", function() {\r
2045 it("should be true on tab2", function() {\r
2046 expectAria(tab2, 'aria-selected', 'true');\r
2047 });\r
2048 \r
2049 it("should be false on tab1", function() {\r
2050 expectAria(tab1, 'aria-selected', 'false');\r
2051 });\r
2052 });\r
2053 \r
2054 describe("aria-expanded", function() {\r
2055 it("should be true on card2", function() {\r
2056 expectAria(card2, 'aria-expanded', 'true');\r
2057 });\r
2058 \r
2059 it("should be false on card1", function() {\r
2060 expectAria(card1, 'aria-expanded', 'false');\r
2061 });\r
2062 });\r
2063 \r
2064 describe("aria-hidden", function() {\r
2065 it("should be true on card1", function() {\r
2066 expectAria(card1, 'aria-hidden', 'true');\r
2067 });\r
2068 \r
2069 it("should be false on card2", function() {\r
2070 expectAria(card2, 'aria-hidden', 'false');\r
2071 });\r
2072 });\r
2073 });\r
2074 });\r
2075});\r