]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/test/specs/menu/Item.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / test / specs / menu / Item.js
CommitLineData
6527f429
DM
1describe('Ext.menu.Item', function () {\r
2 var menu, item;\r
3\r
4 function makeMenu(itemCfg, menuCfg) {\r
5 menu = Ext.widget(Ext.apply({\r
6 xtype: 'menu',\r
7 items: itemCfg\r
8 }, menuCfg));\r
9 menu.show();\r
10\r
11 item = menu.items.getAt(0);\r
12 }\r
13\r
14 afterEach(function() {\r
15 Ext.destroy(menu, item);\r
16 menu = item = null;\r
17 });\r
18\r
19 function clickItem(theItem, doClick) {\r
20 theItem = theItem || item;\r
21 jasmine.fireMouseEvent(theItem.itemEl.dom, 'click');\r
22 \r
23 // Simulated events does not cause default action on anchors with href\r
24 if (doClick) {\r
25 theItem.itemEl.dom.click();\r
26 }\r
27 }\r
28\r
29 describe('on click', function () {\r
30 describe("click event/handler", function() {\r
31 var spy;\r
32\r
33 beforeEach(function() {\r
34 spy = jasmine.createSpy();\r
35 });\r
36\r
37 afterEach(function() {\r
38 spy = null;\r
39 });\r
40\r
41 describe("handler", function() {\r
42 it("should fire the handler", function() {\r
43 makeMenu({\r
44 text: 'Foo',\r
45 handler: spy\r
46 });\r
47 clickItem();\r
48 expect(spy.callCount).toBe(1);\r
49 });\r
50\r
51 it("should not fire when disabled", function() {\r
52 makeMenu({\r
53 text: 'Foo',\r
54 handler: spy,\r
55 disabled: true\r
56 });\r
57 clickItem();\r
58 expect(spy).not.toHaveBeenCalled();\r
59 });\r
60\r
61 it("should pass the item and the event object", function() {\r
62 makeMenu({\r
63 text: 'Foo',\r
64 handler: spy\r
65 });\r
66 clickItem();\r
67\r
68 var args = spy.mostRecentCall.args;\r
69 expect(args[0]).toBe(item);\r
70 expect(args[1] instanceof Ext.event.Event).toBe(true);\r
71 });\r
72\r
73 it("should default the scope to the item", function() {\r
74 makeMenu({\r
75 text: 'Foo',\r
76 handler: spy\r
77 });\r
78 clickItem();\r
79 expect(spy.mostRecentCall.object).toBe(item);\r
80 });\r
81\r
82 it("should used the passed scope", function() {\r
83 var o = {};\r
84 makeMenu({\r
85 text: 'Foo',\r
86 scope: o,\r
87 handler: spy\r
88 });\r
89 clickItem();\r
90 expect(spy.mostRecentCall.object).toBe(o);\r
91 });\r
92\r
93 it("should be able to route the handler to a view controller", function() {\r
94 var ctrl = new Ext.app.ViewController();\r
95 ctrl.onFoo = spy;\r
96 makeMenu({\r
97 text: 'Foo',\r
98 handler: 'onFoo'\r
99 }, {\r
100 controller: ctrl\r
101 });\r
102 clickItem();\r
103 expect(spy.callCount).toBe(1);\r
104 });\r
105\r
106 it("should have the menu hidden when the handler fires with hideOnClick: true", function() {\r
107 var visible;\r
108 makeMenu({\r
109 text: 'Foo',\r
110 handler: spy.andCallFake(function() {\r
111 visible = menu.isVisible();\r
112 })\r
113 });\r
114 clickItem();\r
115 expect(visible).toBe(false);\r
116 });\r
117\r
118 it("should fire the handler after the click event", function() {\r
119 var order = [];\r
120 makeMenu({\r
121 text: 'Foo',\r
122 listeners: {\r
123 click: function() {\r
124 order.push('click');\r
125 }\r
126 },\r
127 handler: function() {\r
128 order.push('handler')\r
129 }\r
130 });\r
131 clickItem();\r
132 expect(order).toEqual(['click', 'handler']);\r
133 });\r
134\r
135 it("should not call the handler if the click event returns false", function() {\r
136 makeMenu({\r
137 text: 'Foo',\r
138 listeners: {\r
139 click: function() {\r
140 return false;\r
141 }\r
142 },\r
143 handler: spy\r
144 });\r
145 clickItem();\r
146 expect(spy).not.toHaveBeenCalled();\r
147 });\r
148\r
149 it("it should not fire the callback if the menu is destroyed in the click event", function() {\r
150 makeMenu({\r
151 text: 'Foo',\r
152 listeners: {\r
153 click: function() {\r
154 menu.destroy();\r
155 }\r
156 },\r
157 handler: spy\r
158 });\r
159 clickItem();\r
160 expect(spy).not.toHaveBeenCalled();\r
161 });\r
162 });\r
163\r
164 describe("click event", function() {\r
165 it("should fire the click event", function() {\r
166 makeMenu({\r
167 text: 'Foo',\r
168 listeners: {\r
169 click: spy\r
170 }\r
171 });\r
172 clickItem();\r
173 expect(spy.callCount).toBe(1);\r
174 });\r
175\r
176 it("should not fire when disabled", function() {\r
177 makeMenu({\r
178 text: 'Foo',\r
179 listeners: {\r
180 click: spy\r
181 },\r
182 disabled: true\r
183 });\r
184 clickItem();\r
185 expect(spy).not.toHaveBeenCalled();\r
186 });\r
187\r
188 it("should pass the item and the event object", function() {\r
189 makeMenu({\r
190 text: 'Foo',\r
191 listeners: {\r
192 click: spy\r
193 }\r
194 });\r
195 clickItem();\r
196\r
197 var args = spy.mostRecentCall.args;\r
198 expect(args[0]).toBe(item);\r
199 expect(args[1] instanceof Ext.event.Event).toBe(true);\r
200 });\r
201\r
202 it("should have the menu hidden when the handler fires with hideOnClick: true", function() {\r
203 var visible;\r
204 makeMenu({\r
205 text: 'Foo',\r
206 listeners: {\r
207 click: spy.andCallFake(function() {\r
208 visible = menu.isVisible();\r
209 })\r
210 }\r
211 });\r
212 clickItem();\r
213 expect(visible).toBe(false);\r
214 });\r
215 });\r
216 });\r
217\r
218 describe("hideOnClick", function() {\r
219 it("should hide the menu with hideOnClick: true", function() {\r
220 makeMenu({\r
221 text: 'Foo',\r
222 hideOnClick: true\r
223 });\r
224 clickItem();\r
225 expect(menu.isVisible()).toBe(false);\r
226 });\r
227\r
228 it("should not hide the menu with hideOnClick: false", function() {\r
229 makeMenu({\r
230 text: 'Foo',\r
231 hideOnClick: false\r
232 });\r
233 clickItem();\r
234 expect(menu.isVisible()).toBe(true);\r
235 });\r
236\r
237 describe("hierarchy", function() {\r
238 function expand(item) {\r
239 item.activated = true;\r
240 item.expandMenu(null, 0);\r
241\r
242 return item.menu;\r
243 }\r
244 it("should hide a parent menu", function() {\r
245 makeMenu({\r
246 text: 'Foo',\r
247 menu: {\r
248 items: [{\r
249 text: 'Bar'\r
250 }]\r
251 }\r
252 });\r
253\r
254 var item = menu.items.first(),\r
255 subMenu = item.menu;\r
256\r
257 expand(item);\r
258 clickItem(subMenu.items.first());\r
259 expect(subMenu.isVisible()).toBe(false);\r
260 expect(menu.isVisible()).toBe(false);\r
261 });\r
262\r
263 it("should hide all parent menus", function() {\r
264 makeMenu({\r
265 text: 'Foo',\r
266 menu: {\r
267 items: {\r
268 text: 'Bar',\r
269 menu: {\r
270 items: {\r
271 text: 'Baz',\r
272 menu: {\r
273 items: {\r
274 text: 'Qux'\r
275 }\r
276 }\r
277 }\r
278 }\r
279 }\r
280 }\r
281 });\r
282\r
283 var sub1 = expand(menu.items.first()),\r
284 sub2 = expand(sub1.items.first()),\r
285 sub3 = expand(sub2.items.first());\r
286\r
287 clickItem(sub3.items.first());\r
288\r
289 expect(sub3.isVisible()).toBe(false);\r
290 expect(sub2.isVisible()).toBe(false);\r
291 expect(sub1.isVisible()).toBe(false);\r
292 expect(menu.isVisible()).toBe(false);\r
293 });\r
294 });\r
295 });\r
296\r
297 describe('href property', function () {\r
298 // Note that the specs were failing in FF 24 without the waitsFor().\r
299 // Note that it's necessary to set the activeItem and focusedItem to test the API!\r
300 var menuItem;\r
301\r
302 afterEach(function () {\r
303 menuItem = null;\r
304 location.hash = '';\r
305 });\r
306\r
307 it('should follow the target', function () {\r
308 makeMenu([{\r
309 text: 'menu item one',\r
310 href: '#ledzep'\r
311 }, {\r
312 text: 'menu item two'\r
313 }]);\r
314\r
315 menu.activeItem = menu.focusedItem = item;\r
316 clickItem(item, Ext.isIE9m);\r
317\r
318 waitsFor(function () {\r
319 return location.hash === '#ledzep';\r
320 }, 'timed out waiting for hash to change', 1000);\r
321\r
322 runs(function () {\r
323 expect(location.hash).toBe('#ledzep');\r
324 });\r
325 });\r
326 \r
327 // TODO This test does not work properly in IE10+ due to events being translated\r
328 (Ext.isIE10p ? xit : it)('should not follow the target link if the click listener stops the event', function () {\r
329 var hashValue = Ext.isIE ? '#' : '';\r
330\r
331 makeMenu([{\r
332 text: 'menu item one',\r
333 href: '#motley',\r
334 listeners: {\r
335 click: function (cmp, e) {\r
336 e.preventDefault();\r
337 }\r
338 }\r
339 }, {\r
340 text: 'menu item two'\r
341 }]);\r
342\r
343 menu.activeItem = menu.focusedItem = item;\r
344 clickItem(item, Ext.isIE9m);\r
345\r
346 waitsFor(function () {\r
347 return location.hash === hashValue;\r
348 }, 'timed out waiting for hash to change', 1000);\r
349\r
350 runs(function () {\r
351 expect(location.hash).toBe(hashValue);\r
352 });\r
353 });\r
354 });\r
355 });\r
356\r
357 describe('disabled', function () {\r
358 describe('when item has an href config', function () {\r
359 it('should stop the event', function () {\r
360 makeMenu({\r
361 disabled: true,\r
362 href: '#menu'\r
363 });\r
364 clickItem();\r
365 expect(location.hash).not.toBe('menu');\r
366 });\r
367 });\r
368\r
369 it("should gain focus but not activate on mouseover", function() {\r
370 makeMenu([{\r
371 text: 'Foo',\r
372 disabled: true\r
373 }]);\r
374 var item = menu.items.getAt(0);\r
375 jasmine.fireMouseEvent(item.getEl(), 'mouseover');\r
376 waitsFor(function() {\r
377 return item.containsFocus === true;\r
378 }, "Never focused");\r
379 runs(function() {\r
380 expect(item.activated).toBe(false);\r
381 });\r
382 });\r
383\r
384 describe("submenu", function() {\r
385 it("should not show a submenu on mouseover", function() {\r
386 makeMenu([{\r
387 text: 'Foo',\r
388 disabled: true,\r
389 menuExpandDelay: 0,\r
390 menu: {\r
391 items: [{\r
392 text: 'Sub1'\r
393 }]\r
394 }\r
395 }]);\r
396\r
397 var item = menu.items.getAt(0),\r
398 sub = item.getMenu();\r
399\r
400 jasmine.fireMouseEvent(item.getEl(), 'mouseover');\r
401 waitsFor(function() {\r
402 return item.containsFocus === true;\r
403 }, "Never focused");\r
404 runs(function() {\r
405 expect(sub.isVisible()).toBe(false);\r
406 });\r
407 });\r
408 });\r
409 });\r
410\r
411 describe('when destroying', function () {\r
412 var m;\r
413\r
414 beforeEach(function () {\r
415 m = new Ext.menu.Menu();\r
416\r
417 makeMenu([{\r
418 text: 'The Office, UK',\r
419 menu: m\r
420 }]);\r
421\r
422 item.destroy();\r
423\r
424 });\r
425\r
426 afterEach(function () {\r
427 m = null;\r
428 });\r
429\r
430 it('should destroy its menu', function () {\r
431 expect(m.destroyed).toBe(true);\r
432 });\r
433\r
434 it('should cleanup its menu reference', function () {\r
435 expect(item.menu).toBe(null);\r
436 });\r
437 });\r
438\r
439 describe("binding", function() {\r
440 it("should be able to bind properties higher up in the hierarchy", function() {\r
441 var vm = new Ext.app.ViewModel({\r
442 data: {\r
443 title: 'someTitle'\r
444 }\r
445 });\r
446 makeMenu({\r
447 text: 'Foo',\r
448 menu: {\r
449 bind: {\r
450 title: '{title}'\r
451 }\r
452 }\r
453 }, {\r
454 viewModel: vm\r
455 });\r
456 var subMenu = item.menu;\r
457 // Render to force the VM to fire\r
458 subMenu.show();\r
459 vm.notify();\r
460 expect(subMenu.getTitle()).toBe('someTitle');\r
461 });\r
462 });\r
463 \r
464 describe("ARIA", function() {\r
465 function expectAria(attr, value) {\r
466 jasmine.expectAriaAttr(item, attr, value);\r
467 }\r
468 \r
469 function expectNoAria(attr) {\r
470 jasmine.expectNoAriaAttr(item, attr);\r
471 }\r
472 \r
473 describe("simple", function() {\r
474 beforeEach(function() {\r
475 makeMenu({\r
476 text: 'foo'\r
477 });\r
478 \r
479 menu.show();\r
480 });\r
481 \r
482 it("should have itemEl as ariaEl", function() {\r
483 expect(item.ariaEl).toBe(item.itemEl);\r
484 });\r
485 \r
486 it("should have menuitem role", function() {\r
487 expectAria('role', 'menuitem');\r
488 });\r
489 \r
490 it("should not have aria-haspopup", function() {\r
491 expectNoAria('aria-haspopup');\r
492 });\r
493 \r
494 it("should not have aria-owns", function() {\r
495 expectNoAria('aria-owns');\r
496 });\r
497 });\r
498 \r
499 describe("plain", function() {\r
500 beforeEach(function() {\r
501 makeMenu({\r
502 text: 'plain',\r
503 plain: true\r
504 });\r
505 \r
506 menu.show();\r
507 });\r
508 \r
509 it("should have el as ariaEl", function() {\r
510 expect(item.ariaEl).toBe(item.el);\r
511 });\r
512 \r
513 it("should have menuitem role", function() {\r
514 expectAria('role', 'menuitem');\r
515 });\r
516\r
517 it("should not have aria-haspopup", function() {\r
518 expectNoAria('aria-haspopup');\r
519 });\r
520 \r
521 it("should not have aria-owns", function() {\r
522 expectNoAria('aria-owns');\r
523 });\r
524 });\r
525 \r
526 describe("with submenu", function() {\r
527 describe("via config", function() {\r
528 beforeEach(function() {\r
529 makeMenu({\r
530 text: 'submenu',\r
531 menu: {\r
532 items: [{\r
533 text: 'sub-item'\r
534 }]\r
535 }\r
536 });\r
537 \r
538 menu.show();\r
539 });\r
540 \r
541 it("should have aria-haspopup", function() {\r
542 expectAria('aria-haspopup', 'true');\r
543 });\r
544 \r
545 it("should have aria-owns", function() {\r
546 expectAria('aria-owns', item.menu.id);\r
547 });\r
548 });\r
549 \r
550 describe("adding via setMenu", function() {\r
551 beforeEach(function() {\r
552 makeMenu({\r
553 text: 'submenu'\r
554 });\r
555 });\r
556 \r
557 describe("before rendering", function() {\r
558 beforeEach(function() {\r
559 item.setMenu({\r
560 items: [{\r
561 text: 'sub-item'\r
562 }]\r
563 });\r
564 \r
565 menu.show();\r
566 });\r
567 \r
568 it("should have aria-haspopup", function() {\r
569 expectAria('aria-haspopup', 'true');\r
570 });\r
571 \r
572 it("should have aria-owns", function() {\r
573 expectAria('aria-owns', item.menu.id);\r
574 });\r
575 });\r
576 \r
577 describe("after rendering", function() {\r
578 beforeEach(function() {\r
579 menu.show();\r
580 \r
581 item.setMenu({\r
582 items: [{\r
583 text: 'sub-item'\r
584 }]\r
585 });\r
586 });\r
587 \r
588 it("should have aria-haspopup", function() {\r
589 expectAria('aria-haspopup', 'true');\r
590 });\r
591 \r
592 it("should have aria-owns", function() {\r
593 expectAria('aria-owns', item.menu.id);\r
594 });\r
595 });\r
596 });\r
597 \r
598 describe("removing via setMenu", function() {\r
599 beforeEach(function() {\r
600 makeMenu({\r
601 text: 'submenu',\r
602 menu: {\r
603 items: [{\r
604 text: 'sub-item'\r
605 }]\r
606 }\r
607 });\r
608 });\r
609 \r
610 describe("before rendering", function() {\r
611 beforeEach(function() {\r
612 item.setMenu(null);\r
613 });\r
614 \r
615 it("should not have aria-haspopup", function() {\r
616 expectNoAria('aria-haspopup');\r
617 });\r
618 \r
619 it("should have no aria-owns", function() {\r
620 expectNoAria('aria-owns');\r
621 });\r
622 });\r
623 \r
624 describe("after rendering", function() {\r
625 beforeEach(function() {\r
626 menu.show();\r
627 item.setMenu(null);\r
628 });\r
629 \r
630 it("should not have aria-haspopup", function() {\r
631 expectNoAria('aria-haspopup');\r
632 });\r
633 \r
634 it("should not have aria-owns", function() {\r
635 expectNoAria('aria-owns');\r
636 });\r
637 });\r
638 });\r
639 });\r
640 });\r
641});\r