UNPKG

angular-material-npfixed

Version:

The Angular Material project is an implementation of Material Design in Angular.js. This project provides a set of reusable, well-tested, and accessible Material Design UI components. Angular Material is supported internally at Google by the Angular.js, M

362 lines (289 loc) 11.3 kB
describe('mdNavBar', function() { var el, $compile, $scope, $timeout, ctrl, tabContainer, $material, $mdConstant; /** @ngInject */ var injectLocals = function( _$compile_, $rootScope, _$timeout_, _$material_, _$mdConstant_) { $compile = _$compile_; $scope = $rootScope.$new(); $timeout = _$timeout_; $material = _$material_; $mdConstant = _$mdConstant_; }; beforeEach(function() { module('material.components.navBar', 'ngAnimateMock'); inject(injectLocals); }); afterEach(function() { el && el.remove(); }); function create(template) { el = $compile(template)($scope); angular.element(document.body).append(el); $scope.$apply(); ctrl = el.controller('mdNavBar'); tabContainer = angular.element(el[0].querySelector('._md-nav-bar-list')); $timeout.flush(); $material.flushOutstandingAnimations(); } function createTabs() { create( '<md-nav-bar md-selected-nav-item="selectedTabRoute" ' + ' md-no-ink-bar="noInkBar" ' + ' nav-bar-aria-label="{{ariaLabel}}">' + ' <md-nav-item md-nav-href="#1" name="tab1">' + ' tab1' + ' </md-nav-item>' + ' <md-nav-item md-nav-href="#2" name="tab2">' + ' tab2' + ' </md-nav-item>' + ' <md-nav-item md-nav-href="#3" name="tab3" aria-label="foo">' + ' tab3' + ' </md-nav-item>' + '</md-nav-bar>'); } describe('tabs', function() { it('shows current tab as selected', function() { $scope.selectedTabRoute = 'tab1'; createTabs(); var tab1 = getTab('tab1'); expect(tab1).toHaveClass('md-active'); expect(tab1).toHaveClass('md-primary'); }); it('shows non-selected tabs as unselected', function() { $scope.selectedTabRoute = 'tab1'; createTabs(); expect(getTab('tab2')).toHaveClass('md-unselected'); expect(getTab('tab3')).toHaveClass('md-unselected'); }); it('changes current tab when selectedTabRoute changes', function() { $scope.selectedTabRoute = 'tab1'; createTabs(); updateSelectedTabRoute('tab2'); expect(getTab('tab2')).toHaveClass('md-active'); expect(getTab('tab2')).toHaveClass('md-primary'); expect(getTab('tab1')).not.toHaveClass('md-active'); expect(getTab('tab1')).not.toHaveClass('md-primary'); }); it('does not select tabs when selectedTabRoute is empty', function() { $scope.selectedTabRoute = 'tab1'; createTabs(); updateSelectedTabRoute(''); expect(getTab('tab3')).not.toHaveClass('md-active'); expect(getTab('tab3')).not.toHaveClass('md-primary'); expect(getTab('tab2')).not.toHaveClass('md-active'); expect(getTab('tab2')).not.toHaveClass('md-primary'); expect(getTab('tab1')).not.toHaveClass('md-active'); expect(getTab('tab1')).not.toHaveClass('md-primary'); expect(getInkbarEl().style.display).toBe('none'); updateSelectedTabRoute('tab1'); expect(getTab('tab3')).not.toHaveClass('md-active'); expect(getTab('tab3')).not.toHaveClass('md-primary'); expect(getTab('tab2')).not.toHaveClass('md-active'); expect(getTab('tab2')).not.toHaveClass('md-primary'); expect(getTab('tab1')).toHaveClass('md-active'); expect(getTab('tab1')).toHaveClass('md-primary'); expect(getInkbarEl().style.display).toBe(''); }); it('requires navigation attribute to be present', function() { expect(function() { create('<md-nav-item name="fooo">footab</md-nav-item>'); }).toThrow(); }); it('does not allow multiple navigation attributes', function() { expect(function() { create( '<md-nav-item md-nav-href="a" md-nav-sref="b" name="fooo">' + 'footab</md-nav-item>'); }).toThrow(); }); it('allows empty navigation attribute', function() { // be permissive; this helps with test writing expect(function() { create( '<md-nav-bar>' + '<md-nav-item md-nav-href="" name="fooo">' + 'footab</md-nav-item>' + '<md-nav-bar>'); }).not.toThrow(); }); it('uses nav item text for name if no name supplied', function() { create( '<md-nav-bar md-selected-nav-item="selectedTabRoute" nav-bar-aria-label="{{ariaLabel}}">' + ' <md-nav-item md-nav-href="#1">' + ' footab ' + ' </md-nav-item>' + ' <md-nav-item md-nav-href="#2" name="tab2">' + ' tab2' + ' </md-nav-item>' + ' <md-nav-item md-nav-href="#3" name="tab3">' + ' tab3' + ' </md-nav-item>' + '</md-nav-bar>'); expect(getTab('footab').length).toBe(1); }); it('updates md-selected-nav-item on tab change', function() { $scope.selectedTabRoute = 'tab1'; createTabs(); var tab2Ctrl = getTabCtrl('tab2'); tab2Ctrl.getButtonEl().click(); $scope.$apply(); expect($scope.selectedTabRoute).toBe('tab2'); }); it('adds ui-sref-opts attribute to nav item when sref-opts attribute is ' + 'defined', function() { create( '<md-nav-bar md-selected-nav-item="selected" nav-bar-aria-label="nav">' + '<md-nav-item md-nav-sref="page1">' + 'tab1' + '</md-nav-item>' + '<md-nav-item md-nav-sref="page2" sref-opts="{reload:true,notify:true}">' + 'tab2' + '</md-nav-item>' + '</md-nav-bar>' ); expect(getTab('tab2').attr('ui-sref-opts')) .toBe('{"reload":true,"notify":true}'); }); it('does not update tabs if tab controller is undefined', function() { $scope.selectedTabRoute = 'tab1'; spyOn(Object.getPrototypeOf(ctrl), '_updateInkBarStyles'); spyOn(Object.getPrototypeOf(ctrl), '_getTabs').and.returnValue(null); createTabs(); expect(ctrl._updateInkBarStyles) .not.toHaveBeenCalled(); }); }); describe('inkbar', function() { it('moves to new tab', function() { $scope.selectedTabRoute = 'tab1'; createTabs(); // b/c there is no css in the karma test, we have to interrogate the // inkbar style property directly expect(parseInt(getInkbarEl().style.left)) .toBeCloseTo(getTab('tab1')[0].offsetLeft, 0.1); updateSelectedTabRoute('tab3'); expect(parseInt(getInkbarEl().style.left)) .toBeCloseTo(getTab('tab3')[0].offsetLeft, 0.1); }); it('should hide if md-no-ink-bar is enabled', function() { $scope.noInkBar = false; $scope.selectedTabRoute = 'tab1'; createTabs(); expect(getInkbarEl().offsetParent).toBeTruthy(); $scope.$apply('noInkBar = true'); expect(getInkbarEl().offsetParent).not.toBeTruthy(); $scope.$apply('noInkBar = false'); expect(getInkbarEl().offsetParent).toBeTruthy(); }); }); describe('a11y', function() { it('sets aria-checked on the selected tab', function() { $scope.selectedTabRoute = 'tab1'; createTabs(); expect(getTab('tab1').parent().attr('aria-selected')).toBe('true'); expect(getTab('tab2').parent().attr('aria-selected')).toBe('false'); expect(getTab('tab3').parent().attr('aria-selected')).toBe('false'); updateSelectedTabRoute('tab3'); expect(getTab('tab1').parent().attr('aria-selected')).toBe('false'); expect(getTab('tab2').parent().attr('aria-selected')).toBe('false'); expect(getTab('tab3').parent().attr('aria-selected')).toBe('true'); }); it('sets aria-label on the listbox', function() { var label = 'top level navigation for my site'; $scope.ariaLabel = label; $scope.selectedTabRoute = 'tab1'; createTabs(); expect(tabContainer[0].getAttribute('aria-label')).toBe(label); }); it('sets focus on the selected tab when the navbar receives focus', function() { $scope.selectedTabRoute = 'tab2'; createTabs(); expect(getTab('tab2')).not.toHaveClass('md-focused'); ctrl.onFocus(); $scope.$apply(); expect(getTab('tab2')).toHaveClass('md-focused'); expect(document.activeElement).toBe(getTab('tab2')[0]); }); it('removes tab focus when the tab blurs', function() { $scope.selectedTabRoute = 'tab2'; createTabs(); tabContainer.triggerHandler('focus'); expect(getTab('tab2')).toHaveClass('md-focused'); getTab('tab2').triggerHandler('blur'); expect(getTab('tab2')).not.toHaveClass('md-focused'); }); it('up/left moves focus back', function() { $scope.selectedTabRoute = 'tab3'; createTabs(); tabContainer.triggerHandler('focus'); tabContainer.triggerHandler({ type: 'keydown', keyCode: $mdConstant.KEY_CODE.UP_ARROW, }); tabContainer.triggerHandler({ type: 'keydown', keyCode: $mdConstant.KEY_CODE.LEFT_ARROW, }); $scope.$apply(); expect(getTab('tab1')).toHaveClass('md-focused'); expect(document.activeElement).toBe(getTab('tab1')[0]); expect(getTab('tab2')).not.toHaveClass('md-focused'); expect(getTab('tab3')).not.toHaveClass('md-focused'); }); it('down/right moves focus forward', function() { $scope.selectedTabRoute = 'tab1'; createTabs(); tabContainer.triggerHandler('focus'); tabContainer.triggerHandler({ type: 'keydown', keyCode: $mdConstant.KEY_CODE.DOWN_ARROW, }); tabContainer.triggerHandler({ type: 'keydown', keyCode: $mdConstant.KEY_CODE.RIGHT_ARROW, }); $scope.$apply(); expect(getTab('tab1')).not.toHaveClass('md-focused'); expect(getTab('tab2')).not.toHaveClass('md-focused'); expect(getTab('tab3')).toHaveClass('md-focused'); expect(document.activeElement).toBe(getTab('tab3')[0]); }); it('enter selects a tab', function() { $scope.selectedTabRoute = 'tab2'; createTabs(); var tab2Ctrl = getTabCtrl('tab2'); spyOn(tab2Ctrl.getButtonEl(), 'click'); tabContainer.triggerHandler('focus'); tabContainer.triggerHandler({ type: 'keydown', keyCode: $mdConstant.KEY_CODE.ENTER, }); $scope.$apply(); $timeout.flush(); expect(tab2Ctrl.getButtonEl().click).toHaveBeenCalled(); }); it('automatically adds label to nav items', function() { createTabs(); expect(getTab('tab1').parent().attr('aria-label')).toBe('tab1'); expect(getTab('tab2').parent().attr('aria-label')).toBe('tab2'); }); it('does not change aria-label on nav items', function() { createTabs(); expect(getTab('tab3').parent().attr('aria-label')).toBe('foo'); }); }); function getTab(tabName) { return angular.element(getTabCtrl(tabName).getButtonEl()); } function getTabCtrl(tabName) { return ctrl._getTabByName(tabName); } function getInkbarEl() { return el.find('md-nav-ink-bar')[0]; } function updateSelectedTabRoute(newRoute) { $scope.selectedTabRoute = newRoute; $scope.$apply(); $timeout.flush(); } });