UNPKG

angular-ui-bootstrap

Version:

Native AngularJS (Angular) directives for Bootstrap

947 lines (798 loc) 35.8 kB
describe('uib-dropdown', function() { var $animate, $compile, $rootScope, $document, $templateCache, dropdownConfig, element, $browser, $log; beforeEach(module('ngAnimateMock')); beforeEach(module('ui.bootstrap.dropdown')); beforeEach(inject(function(_$animate_, _$compile_, _$rootScope_, _$document_, _$templateCache_, uibDropdownConfig, _$browser_, _$log_) { $animate = _$animate_; $compile = _$compile_; $rootScope = _$rootScope_; $document = _$document_; $templateCache = _$templateCache_; dropdownConfig = uibDropdownConfig; $browser = _$browser_; $log = _$log_; })); afterEach(function() { element.remove(); }); var clickDropdownToggle = function(elm) { elm = elm || element; elm.find('a[uib-dropdown-toggle]').click(); }; var triggerKeyDown = function (element, keyCode) { var e = $.Event('keydown'); spyOn(e, 'stopPropagation'); e.stopPropagation.and.callThrough(); e.which = keyCode; element.trigger(e); return e; }; describe('basic', function() { function dropdown() { return $compile('<li uib-dropdown><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li><a href>Hello</a></li></ul></li>')($rootScope); } beforeEach(function() { element = dropdown(); }); it('should toggle on `a` click', function() { expect(element).not.toHaveClass(dropdownConfig.openClass); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); clickDropdownToggle(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); it('should toggle when an option is clicked', function() { $document.find('body').append(element); expect(element).not.toHaveClass(dropdownConfig.openClass); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); var optionEl = element.find('ul > li').eq(0).find('a').eq(0); optionEl.click(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); it('should close on document click', function() { clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); $document.click(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); it('should close on escape key & focus toggle element', function() { var dropdownMenu = element.find('[uib-dropdown-menu]'); $document.find('body').append(element); clickDropdownToggle(); var event = triggerKeyDown(dropdownMenu, 27); expect(element).not.toHaveClass(dropdownConfig.openClass); expect(element.find('a')).toHaveFocus(); expect(event.stopPropagation).toHaveBeenCalled(); }); it('should not close on backspace key', function() { clickDropdownToggle(); triggerKeyDown(element, 8); expect(element).toHaveClass(dropdownConfig.openClass); }); it('should not close on right click', function() { clickDropdownToggle(); element.find('ul a').trigger({ type: 'mousedown', which: 3 }); expect(element).toHaveClass(dropdownConfig.openClass); }); it('should only allow one dropdown to be open at once', function() { var elm1 = dropdown(); var elm2 = dropdown(); expect(elm1).not.toHaveClass(dropdownConfig.openClass); expect(elm2).not.toHaveClass(dropdownConfig.openClass); clickDropdownToggle(elm1); expect(elm1).toHaveClass(dropdownConfig.openClass); expect(elm2).not.toHaveClass(dropdownConfig.openClass); clickDropdownToggle(elm2); expect(elm1).not.toHaveClass(dropdownConfig.openClass); expect(elm2).toHaveClass(dropdownConfig.openClass); }); it('should not toggle if the element has `disabled` class', function() { var elm = $compile('<li uib-dropdown><a class="disabled" uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope); clickDropdownToggle( elm ); expect(elm).not.toHaveClass(dropdownConfig.openClass); }); it('should not toggle if the element is disabled', function() { var elm = $compile('<li uib-dropdown><button disabled="disabled" uib-dropdown-toggle></button><ul><li>Hello</li></ul></li>')($rootScope); elm.find('button').click(); expect(elm).not.toHaveClass(dropdownConfig.openClass); }); it('should not toggle if the element has `ng-disabled` as true', function() { $rootScope.isdisabled = true; var elm = $compile('<li uib-dropdown><div ng-disabled="isdisabled" uib-dropdown-toggle></div><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope); $rootScope.$digest(); elm.find('div').click(); expect(elm).not.toHaveClass(dropdownConfig.openClass); $rootScope.isdisabled = false; $rootScope.$digest(); elm.find('div').click(); expect(elm).toHaveClass(dropdownConfig.openClass); }); it('should unbind events on scope destroy', function() { var $scope = $rootScope.$new(); var elm = $compile('<li uib-dropdown><button ng-disabled="isdisabled" uib-dropdown-toggle></button><ul uib-dropdown-menu><li>Hello</li></ul></li>')($scope); $scope.$digest(); var buttonEl = elm.find('button'); buttonEl.click(); expect(elm).toHaveClass(dropdownConfig.openClass); buttonEl.click(); expect(elm).not.toHaveClass(dropdownConfig.openClass); $scope.$destroy(); buttonEl.click(); expect(elm).not.toHaveClass(dropdownConfig.openClass); }); // issue 270 it('executes other document click events normally', function() { var checkboxEl = $compile('<input type="checkbox" ng-click="clicked = true" />')($rootScope); $rootScope.$digest(); expect(element).not.toHaveClass(dropdownConfig.openClass); expect($rootScope.clicked).toBeFalsy(); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); expect($rootScope.clicked).toBeFalsy(); checkboxEl.click(); expect($rootScope.clicked).toBeTruthy(); }); // WAI-ARIA it('should aria markup to the `dropdown-toggle`', function() { var toggleEl = element.find('a'); expect(toggleEl.attr('aria-haspopup')).toBe('true'); expect(toggleEl.attr('aria-expanded')).toBe('false'); clickDropdownToggle(); expect(toggleEl.attr('aria-expanded')).toBe('true'); clickDropdownToggle(); expect(toggleEl.attr('aria-expanded')).toBe('false'); }); // pr/issue 3274 it('should not raise $digest:inprog if dismissed during a digest cycle', function() { clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); $rootScope.$apply(function() { $document.click(); }); expect(element).not.toHaveClass(dropdownConfig.openClass); }); }); describe('using dropdownMenuTemplate', function() { function dropdown() { $templateCache.put('custom.html', '<ul class="uib-dropdown-menu"><li>Item 1</li></ul>'); return $compile('<li uib-dropdown><a href uib-dropdown-toggle></a><ul uib-dropdown-menu template-url="custom.html"></ul></li>')($rootScope); } beforeEach(function() { element = dropdown(); }); it('should apply custom template for dropdown menu', function() { element.find('a').click(); expect(element.find('ul.uib-dropdown-menu').eq(0).find('li').eq(0).text()).toEqual('Item 1'); }); it('should clear ul when dropdown menu is closed', function() { element.find('a').click(); expect(element.find('ul.uib-dropdown-menu').eq(0).find('li').eq(0).text()).toEqual('Item 1'); element.find('a').click(); expect(element.find('ul.uib-dropdown-menu').eq(0).find('li').length).toEqual(0); }); }); describe('using dropdown-append-to-body', function() { describe('with no value', function() { function dropdown() { return $compile('<li uib-dropdown dropdown-append-to-body><a href uib-dropdown-toggle></a><ul uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Body</a></li></ul></li>')($rootScope); } beforeEach(function() { element = dropdown(); $document.find('body').append(element); }); afterEach(function() { element.remove(); }); it('does not add the menu to the body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); describe('when toggled open', function() { var toggle; beforeEach(function() { toggle = element.find('[uib-dropdown-toggle]'); toggle.trigger('click'); }); it('adds the menu to the body', function() { expect($document.find('#dropdown-menu').parent()[0]).toBe($document.find('body')[0]); }); describe('when toggled closed', function() { beforeEach(function() { toggle.trigger('click'); }); it('removes the menu from body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); describe('when closed by clicking on menu', function() { var menu; beforeEach(function() { menu = $document.find('#dropdown-menu a'); menu.focus(); menu.trigger('click'); }); it('focuses the dropdown element on close', function() { expect(document.activeElement).toBe(toggle[0]); }); it('removes the menu from body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); describe('when the dropdown is removed', function() { beforeEach(function() { element.remove(); $rootScope.$digest(); }); it('removes the menu from body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); }); }); describe('with a value', function() { function dropdown() { return $compile('<li uib-dropdown dropdown-append-to-body="appendToBody"><a href uib-dropdown-toggle></a><ul uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Body</a></li></ul></li>')($rootScope); } describe('that is not false', function() { beforeEach(function() { $rootScope.appendToBody = 'sure'; element = dropdown(); $document.find('body').append(element); }); afterEach(function() { element.remove(); }); it('does not add the menu to the body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); describe('when toggled open', function() { var toggle; beforeEach(function() { toggle = element.find('[uib-dropdown-toggle]'); toggle.trigger('click'); }); it('adds the menu to the body', function() { expect($document.find('#dropdown-menu').parent()[0]).toBe($document.find('body')[0]); }); describe('when toggled closed', function() { beforeEach(function() { toggle.trigger('click'); }); it('removes the menu from body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); describe('when closed by clicking on menu', function() { var menu; beforeEach(function() { menu = $document.find('#dropdown-menu a'); menu.focus(); menu.trigger('click'); }); it('focuses the dropdown element on close', function() { expect(document.activeElement).toBe(toggle[0]); }); it('removes the menu from body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); describe('when the dropdown is removed', function() { beforeEach(function() { element.remove(); $rootScope.$digest(); }); it('removes the menu from body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); }); }); describe('that is false', function() { beforeEach(function() { $rootScope.appendToBody = false; element = dropdown(); $document.find('body').append(element); }); afterEach(function() { element.remove(); }); it('does not add the menu to the body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); describe('when toggled open', function() { var toggle; beforeEach(function() { toggle = element.find('[uib-dropdown-toggle]'); toggle.trigger('click'); }); it('does not add the menu to the body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); describe('when toggled closed', function() { beforeEach(function() { toggle.trigger('click'); }); it('does not remove the menu', function() { expect($document.find('#dropdown-menu').length).not.toEqual(0); }); }); describe('when closed by clicking on menu', function() { var menu; beforeEach(function() { menu = $document.find('#dropdown-menu a'); menu.focus(); menu.trigger('click'); }); it('focuses the dropdown element on close', function() { expect(document.activeElement).toBe(toggle[0]); }); it('does not removes the menu from body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); describe('when the dropdown is removed', function() { beforeEach(function() { element.remove(); $rootScope.$digest(); }); it('removes the menu from body', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); }); }); }); }); describe('using dropdown-append-to', function() { var initialPage, container; function dropdown() { return $compile('<li uib-dropdown dropdown-append-to="appendTo"><a href uib-dropdown-toggle></a><ul class="dropdown-menu" uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Container</a></li></ul></li>')($rootScope); } beforeEach(function() { $document.find('body').append(angular.element('<div id="dropdown-container"></div>')); $rootScope.appendTo = container = $document.find('#dropdown-container'); element = dropdown(); $document.find('body').append(element); }); afterEach(function() { // Cleanup the extra elements we appended $document.find('#dropdown-container').remove(); }); it('does not add the menu to the container', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe(container[0]); }); it('does not add open class on container', function() { expect(container).not.toHaveClass('uib-dropdown-open'); }); describe('when toggled open', function() { var toggle; beforeEach(function() { toggle = element.find('[uib-dropdown-toggle]'); toggle.trigger('click'); }); it('adds the menu to the container', function() { expect($document.find('#dropdown-menu').parent()[0]).toBe(container[0]); }); it('adds open class on container', function() { expect(container).toHaveClass('uib-dropdown-open'); }); describe('when toggled closed', function() { beforeEach(function() { toggle.trigger('click'); }); it('removes the menu from the container', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); it('removes open class from container', function() { expect(container).not.toHaveClass('uib-dropdown-open'); }); }); describe('when closed by clicking on menu', function() { var menu; beforeEach(function() { menu = $document.find('#dropdown-menu a'); menu.focus(); menu.trigger('click'); }); it('focuses the dropdown element on close', function() { expect(document.activeElement).toBe(toggle[0]); }); it('removes the menu from the container', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); it('removes open class from container', function() { expect(container).not.toHaveClass('uib-dropdown-open'); }); }); describe('when the dropdown is removed', function() { beforeEach(function() { element.remove(); $rootScope.$digest(); }); it('removes the menu from the container', function() { expect($document.find('#dropdown-menu').parent()[0]).not.toBe($document.find('body')[0]); }); }); }); }); describe('using dropdown-append-to with two dropdowns', function() { function dropdown() { return $compile('<div><div class="dropdown1" uib-dropdown dropdown-append-to="appendTo" on-toggle="log(1, open)"><a href uib-dropdown-toggle></a><ul class="dropdown-menu" uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Container</a></li></ul></div><div class="dropdown2" uib-dropdown dropdown-append-to="appendTo" on-toggle="log(2, open)"><a href uib-dropdown-toggle></a><ul class="dropdown-menu" uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Container</a></li></ul></div></div>')($rootScope); } beforeEach(function() { $document.find('body').append(angular.element('<div id="dropdown-container"></div>')); $rootScope.appendTo = $document.find('#dropdown-container'); $rootScope.log = jasmine.createSpy('log'); element = dropdown(); $document.find('body').append(element); }); afterEach(function() { // Cleanup the extra elements we appended $document.find('#dropdown-container').remove(); }); it('should keep the class when toggling from one dropdown to another with the same container', function() { var container = $document.find('#dropdown-container'); expect(container).not.toHaveClass('uib-dropdown-open'); element.find('.dropdown1 [uib-dropdown-toggle]').click(); expect(container).toHaveClass('uib-dropdown-open'); element.find('.dropdown2 [uib-dropdown-toggle]').click(); expect(container).toHaveClass('uib-dropdown-open'); }); }); describe('using is-open', function() { describe('with uib-dropdown-toggle', function() { beforeEach(function() { $rootScope.isopen = true; element = $compile('<li uib-dropdown is-open="isopen"><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope); $rootScope.$digest(); }); it('should be open initially', function() { expect(element).toHaveClass(dropdownConfig.openClass); }); it('should change `is-open` binding when toggles', function() { clickDropdownToggle(); expect($rootScope.isopen).toBe(false); }); it('should toggle when `is-open` changes', function() { $rootScope.isopen = false; $rootScope.$digest(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); it('focus toggle element when opening', function() { $document.find('body').append(element); clickDropdownToggle(); $rootScope.isopen = false; $rootScope.$digest(); expect(element.find('a')).not.toHaveFocus(); $rootScope.isopen = true; $rootScope.$digest(); expect(element.find('a')).toHaveFocus(); }); }); describe('without uib-dropdown-toggle', function() { beforeEach(function() { $rootScope.isopen = true; element = $compile('<li uib-dropdown is-open="isopen"><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope); $rootScope.$digest(); }); it('should be open initially', function() { expect(element).toHaveClass(dropdownConfig.openClass); }); it('should toggle when `is-open` changes', function() { $rootScope.isopen = false; $rootScope.$digest(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); }); }); describe('using on-toggle', function() { describe('with is-open to false', function() { beforeEach(function() { $rootScope.toggleHandler = jasmine.createSpy('toggleHandler'); $rootScope.isopen = false; element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)" is-open="isopen"><a uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope); $rootScope.$digest(); }); it('should not have been called initially', function() { expect($rootScope.toggleHandler).not.toHaveBeenCalled(); }); it('should call it correctly when toggles', function() { $rootScope.isopen = true; $rootScope.$digest(); $animate.flush(); $rootScope.$digest(); expect($rootScope.toggleHandler).toHaveBeenCalledWith(true); clickDropdownToggle(); $animate.flush(); $rootScope.$digest(); expect($rootScope.toggleHandler).toHaveBeenCalledWith(false); }); }); describe('with is-open to true', function() { beforeEach(function() { $rootScope.toggleHandler = jasmine.createSpy('toggleHandler'); $rootScope.isopen = true; element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)" is-open="isopen"><a uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope); $rootScope.$digest(); }); it('should not have been called initially', function() { expect($rootScope.toggleHandler).not.toHaveBeenCalled(); }); it('should call it correctly when toggles', function() { $rootScope.isopen = false; $rootScope.$digest(); $animate.flush(); $rootScope.$digest(); expect($rootScope.toggleHandler).toHaveBeenCalledWith(false); $rootScope.isopen = true; $rootScope.$digest(); $animate.flush(); $rootScope.$digest(); expect($rootScope.toggleHandler).toHaveBeenCalledWith(true); }); }); describe('without is-open', function() { beforeEach(function() { $rootScope.toggleHandler = jasmine.createSpy('toggleHandler'); element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)"><a uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope); $rootScope.$digest(); }); it('should not have been called initially', function() { expect($rootScope.toggleHandler).not.toHaveBeenCalled(); }); it('should call it when clicked', function() { clickDropdownToggle(); $animate.flush(); $rootScope.$digest(); expect($rootScope.toggleHandler).toHaveBeenCalledWith(true); clickDropdownToggle(); $animate.flush(); $rootScope.$digest(); expect($rootScope.toggleHandler).toHaveBeenCalledWith(false); }); }); }); describe('using auto-close', function() { function dropdown(autoClose) { return $compile('<li uib-dropdown ' + (autoClose === undefined ? '' : 'auto-close="' + autoClose + '"') + '><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li><a href>Hello</a></li></ul></li>')($rootScope); } describe('always', function() { it('should close on document click if no auto-close is specified', function() { element = dropdown(); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); $document.click(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); it('should close on document click if empty auto-close is specified', function() { element = dropdown(''); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); $document.click(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); }); describe('disabled', function() { it('auto-close="disabled"', function() { element = dropdown('disabled'); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); $document.click(); expect(element).toHaveClass(dropdownConfig.openClass); }); it('control with is-open', function() { $rootScope.isopen = true; element = $compile('<li uib-dropdown is-open="isopen" auto-close="disabled"><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope); $rootScope.$digest(); expect(element).toHaveClass(dropdownConfig.openClass); //should remain open $document.click(); expect(element).toHaveClass(dropdownConfig.openClass); //now should close $rootScope.isopen = false; $rootScope.$digest(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); it('should close anyway if toggle is clicked', function() { element = dropdown('disabled'); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); clickDropdownToggle(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); it('should close anyway if esc is pressed', function() { element = dropdown('disabled'); var dropdownMenu = element.find('[uib-dropdown-menu]'); $document.find('body').append(element); clickDropdownToggle(); triggerKeyDown(dropdownMenu, 27); expect(element).not.toHaveClass(dropdownConfig.openClass); expect(element.find('a')).toHaveFocus(); }); it('should close anyway if another dropdown is opened', function() { var elm1 = dropdown('disabled'); var elm2 = dropdown(); expect(elm1).not.toHaveClass(dropdownConfig.openClass); expect(elm2).not.toHaveClass(dropdownConfig.openClass); clickDropdownToggle(elm1); expect(elm1).toHaveClass(dropdownConfig.openClass); expect(elm2).not.toHaveClass(dropdownConfig.openClass); clickDropdownToggle(elm2); expect(elm1).not.toHaveClass(dropdownConfig.openClass); expect(elm2).toHaveClass(dropdownConfig.openClass); }); }); describe('outsideClick', function() { it('should close only on a click outside of the dropdown menu', function() { element = dropdown('outsideClick'); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); element.find('ul li a').click(); expect(element).toHaveClass(dropdownConfig.openClass); $document.click(); expect(element).not.toHaveClass(dropdownConfig.openClass); }); it('should work with dropdown-append-to-body', function() { element = $compile('<li uib-dropdown dropdown-append-to-body auto-close="outsideClick"><a href uib-dropdown-toggle></a><ul uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Body</a></li></ul></li>')($rootScope); clickDropdownToggle(); var dropdownMenu = $document.find('#dropdown-menu'); expect(dropdownMenu.parent()).toHaveClass(dropdownConfig.appendToOpenClass); dropdownMenu.find('li').eq(0).trigger('click'); expect(dropdownMenu.parent()).toHaveClass(dropdownConfig.appendToOpenClass); $document.click(); expect(dropdownMenu.parent()).not.toHaveClass(dropdownConfig.appendToOpenClass); }); }); }); describe('using keyboard-nav', function() { function dropdown() { return $compile('<li uib-dropdown keyboard-nav><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li><a href>Hello</a></li><li><a href>Hello Again</a></li></ul></li>')($rootScope); } function getFocusedElement() { return angular.element(document.activeElement); } beforeEach(function() { element = dropdown(); }); it('should focus first list element when down arrow pressed', function() { $document.find('body').append(element); clickDropdownToggle(); triggerKeyDown(getFocusedElement(), 40); expect(element).toHaveClass(dropdownConfig.openClass); var optionEl = element.find('ul').eq(0).find('a').eq(0); expect(optionEl).toHaveFocus(); }); it('should not focus first list element when down arrow pressed if closed', function() { $document.find('body').append(element); triggerKeyDown(getFocusedElement(), 40); expect(element).not.toHaveClass(dropdownConfig.openClass); var focusEl = element.find('ul').eq(0).find('a').eq(0); expect(focusEl).not.toHaveFocus(); }); it('should focus second list element when down arrow pressed twice', function() { $document.find('body').append(element); clickDropdownToggle(); triggerKeyDown(getFocusedElement(), 40); triggerKeyDown(getFocusedElement(), 40); expect(element).toHaveClass(dropdownConfig.openClass); var focusEl = element.find('ul').eq(0).find('a').eq(1); expect(focusEl).toHaveFocus(); }); it('should not focus first list element when up arrow pressed after dropdown toggled', function() { $document.find('body').append(element); clickDropdownToggle(); expect(element).toHaveClass(dropdownConfig.openClass); triggerKeyDown(getFocusedElement(), 38); var focusEl = element.find('ul').eq(0).find('a').eq(0); expect(focusEl).not.toHaveFocus(); }); it('should focus last list element when up arrow pressed after dropdown toggled', function() { $document.find('body').append(element); clickDropdownToggle(); triggerKeyDown(getFocusedElement(), 38); expect(element).toHaveClass(dropdownConfig.openClass); var focusEl = element.find('ul').eq(0).find('a').eq(1); expect(focusEl).toHaveFocus(); }); it('should not change focus when other keys are pressed', function() { $document.find('body').append(element); clickDropdownToggle(); triggerKeyDown(getFocusedElement(), 37); expect(element).toHaveClass(dropdownConfig.openClass); var focusEl = element.find('ul').eq(0).find('a'); expect(focusEl[0]).not.toHaveFocus(); expect(focusEl[1]).not.toHaveFocus(); }); it('should focus first list element when down arrow pressed 2x and up pressed 1x', function() { $document.find('body').append(element); clickDropdownToggle(); triggerKeyDown(getFocusedElement(), 40); triggerKeyDown(getFocusedElement(), 40); triggerKeyDown(getFocusedElement(), 38); expect(element).toHaveClass(dropdownConfig.openClass); var focusEl = element.find('ul').eq(0).find('a').eq(0); expect(focusEl).toHaveFocus(); }); it('should stay focused on final list element if down pressed at list end', function() { $document.find('body').append(element); clickDropdownToggle(); triggerKeyDown(getFocusedElement(), 40); triggerKeyDown(getFocusedElement(), 40); expect(element).toHaveClass(dropdownConfig.openClass); var focusEl = element.find('ul').eq(0).find('a').eq(1); expect(focusEl).toHaveFocus(); triggerKeyDown(element, 40); expect(focusEl).toHaveFocus(); }); it('should close if esc is pressed while focused', function() { element = dropdown('disabled'); $document.find('body').append(element); clickDropdownToggle(); triggerKeyDown(getFocusedElement(), 40); expect(element).toHaveClass(dropdownConfig.openClass); var focusEl = element.find('ul').eq(0).find('a').eq(0); expect(focusEl).toHaveFocus(); triggerKeyDown(getFocusedElement(), 27); expect(element).not.toHaveClass(dropdownConfig.openClass); }); describe('with dropdown-append-to-body', function() { function dropdown() { return $compile('<li uib-dropdown dropdown-append-to-body keyboard-nav><a href uib-dropdown-toggle>foo</a><ul uib-dropdown-menu id="dropdown-menu"><li><a href>Hello On Body</a></li><li><a href>Hello Again</a></li></ul></li>')($rootScope); } beforeEach(function() { element = dropdown(); }); it('should focus first list element when down arrow pressed', function() { $document.find('body').append(element); clickDropdownToggle(); var dropdownMenu = $document.find('#dropdown-menu'); triggerKeyDown(getFocusedElement(), 40); expect(dropdownMenu.parent()).toHaveClass(dropdownConfig.appendToOpenClass); var focusEl = $document.find('ul').eq(0).find('a'); expect(focusEl).toHaveFocus(); }); it('should focus second list element when down arrow pressed twice', function() { $document.find('body').append(element); clickDropdownToggle(); var dropdownMenu = $document.find('#dropdown-menu'); triggerKeyDown(getFocusedElement(), 40); triggerKeyDown(getFocusedElement(), 40); triggerKeyDown(getFocusedElement(), 40); expect(dropdownMenu.parent()).toHaveClass(dropdownConfig.appendToOpenClass); var elem1 = $document.find('ul'); var elem2 = elem1.find('a'); var focusEl = $document.find('ul').eq(0).find('a').eq(1); expect(focusEl).toHaveFocus(); }); }); }); // issue #5942 describe('using dropdown-append-to-body with dropdown-menu-right class', function() { function dropdown() { return $compile('<li style="float: right;" uib-dropdown dropdown-append-to-body><a href uib-dropdown-toggle>Toggle menu</a><ul uib-dropdown-menu class="dropdown-menu-right" id="dropdown-menu"><li><a href>Hello On Body</a></li></ul></li>')($rootScope); } beforeEach(function() { element = dropdown(); $document.find('body').append(element); var menu = $document.find('#dropdown-menu'); menu.css('position', 'absolute'); }); afterEach(function() { element.remove(); }); it('should align the menu correctly when the body has no vertical scrollbar', function() { var toggle = element.find('[uib-dropdown-toggle]'); var menu = $document.find('#dropdown-menu'); toggle.trigger('click'); // Get the offsets of the rightmost position of both the toggle and the menu (offset from the left of the window) var toggleRight = Math.round(toggle.offset().left + toggle.outerWidth()); var menuRight = Math.round(menu.offset().left + menu.outerWidth()); expect(menuRight).toBe(toggleRight); }); }); });