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

1,713 lines (1,297 loc) 102 kB
describe('$mdPanel', function() { var $mdPanelProvider, $mdPanel, $rootScope, $rootEl, $templateCache, $q, $material, $mdConstant, $mdUtil, $animate, $$rAF, $window; var panelRef; var attachedElements = []; var PANEL_WRAPPER = '.md-panel-outer-wrapper'; var PANEL_WRAPPER_CLASS = 'md-panel-outer-wrapper'; var PANEL_EL = '.md-panel'; var PANEL_EL_CLASS = 'md-panel'; var HIDDEN_CLASS = '_md-panel-hidden'; var FOCUS_TRAPS_CLASS = '._md-panel-focus-trap'; var FULLSCREEN_CLASS = '_md-panel-fullscreen'; var BACKDROP_CLASS = '._md-panel-backdrop'; var DEFAULT_TEMPLATE = '<div>Hello World!</div>'; var DEFAULT_CONFIG = { template: DEFAULT_TEMPLATE }; var PANEL_ID_PREFIX = 'panel_'; var SCROLL_MASK_CLASS = '.md-scroll-mask'; var ADJUSTED_CLASS = '_md-panel-position-adjusted'; var VIEWPORT_MARGIN = 8; /** * @param {!angular.$injector} $injector * @ngInject */ var injectLocals = function($injector) { $mdPanel = $injector.get('$mdPanel'); $rootScope = $injector.get('$rootScope'); $rootEl = $injector.get('$rootElement'); $templateCache = $injector.get('$templateCache'); $q = $injector.get('$q'); $material = $injector.get('$material'); $mdConstant = $injector.get('$mdConstant'); $mdUtil = $injector.get('$mdUtil'); $animate = $injector.get('$animate'); $window = $injector.get('$window'); $$rAF = $injector.get('$$rAF'); }; beforeEach(function() { module('material.components.panel', 'ngSanitize'); module(['$mdPanelProvider', function(_$mdPanelProvider) { $mdPanelProvider = _$mdPanelProvider; }]); inject(injectLocals); $animate.enabled(false); // By default, the panel is attached to $rootElement, so add it to the DOM. attachToBody($rootEl); }); // Add custom matchers. beforeEach(function() { jasmine.addMatchers({ /** * Asserts that two values are within a range of each other. This is * used for testing relative positioning. If no range is set, defaults * to 1. * * Example Use: * expect(panelTop).toBeApproximately(buttonTop, 1); */ toBeApproximately: function() { return { compare: function(actual, expected, opt_epsilon) { var epsilon = opt_epsilon || 1; var actualNumber = parseFloat(actual); var expectedNumber = parseFloat(expected); var pass = Math.abs(expectedNumber - actualNumber) < epsilon; var not = pass ? 'not ' : ''; return { pass: pass, message: 'Expected ' + expected + not + ' to be within ' + epsilon + ' of ' + actual }; } }; } }); }); afterEach(function() { attachedElements.forEach(function(el) { el.remove(); }); attachedElements = []; if (panelRef && panelRef.isAttached) { panelRef.close(); } // TODO(ErinCoughlan) - Remove when close destroys. panelRef = null; $animate.enabled(true); }); describe('provider logic', function() { var preset = { panelClass: 'preset-container', template: DEFAULT_TEMPLATE }; var preset2 = { panelClass: 'preset2-container', template: DEFAULT_TEMPLATE }; var preset3 = { panelClass: 'preset-container', template: '<div>This is cool!</div>' }; afterEach(function() { $mdPanelProvider.clearPresets(); }); it('should have the $mdPanelProvider available', function() { var provider = $mdPanelProvider; expect(provider).toBeDefined(); }); it('should allow for a custom preset configuration object to be defined ' + 'and stored in the $mdPanelProvider', function() { $mdPanelProvider.definePreset('testPreset', preset); expect(Object.keys($mdPanelProvider.getAllPresets()).length).toBe(1); }); it('should allow for more than one custom preset configuration objects ' + 'to be defined and stored in the $mdPanelProvider', function() { $mdPanelProvider.definePreset('testPreset', preset); $mdPanelProvider.definePreset('testPreset2', preset2); expect(Object.keys($mdPanelProvider.getAllPresets()).length).toBe(2); }); it('should throw if a custom preset configuration object doesn\'t have ' + 'a preset name or proper preset config object', function() { var expression; expression = function() { $mdPanelProvider.definePreset(preset); }; expect(expression).toThrow(); expression = function() { $mdPanelProvider.definePreset('testPreset'); }; expect(expression).toThrow(); }); it('should throw if requesting to define an already defined preset', function() { $mdPanelProvider.definePreset('testPreset', preset); var expression = function() { $mdPanelProvider.definePreset('testPreset', preset); }; expect(expression).toThrow(); }); it('should retrieve and apply a preset when the preset name is provided ' + 'during the create or open method', function() { $mdPanelProvider.definePreset('testPreset', preset); openPanel('testPreset'); expect(PANEL_EL + '.preset-container').toContainHtml('Hello World!'); }); it('should throw if trying to retrieve a preset during the create or ' + 'open method that has not been created', function() { var expression = function() { $mdPanel.create('testPreset'); }; expect(expression).toThrow(); expression = function() { $mdPanel.open('testPreset'); }; expect(expression).toThrow(); }); }); it('should create and open a basic panel', function() { openPanel(DEFAULT_CONFIG); expect(PANEL_EL).toExist(); expect(panelRef.isAttached).toEqual(true); closePanel(); expect(PANEL_EL).not.toExist(); expect(panelRef.isAttached).toEqual(false); }); it('should add and remove a panel from the DOM', function() { expect(PANEL_EL).not.toExist(); openPanel(DEFAULT_CONFIG); expect(PANEL_EL).toExist(); closePanel(); expect(PANEL_EL).not.toExist(); }); it('should remove a panel from the DOM when the scope is destroyed', function() { openPanel(); expect(PANEL_EL).toExist(); panelRef.config.scope.$destroy(); expect(PANEL_EL).not.toExist(); }); it('should hide and show a panel in the DOM', function() { openPanel(DEFAULT_CONFIG); expect(PANEL_EL).toExist(); expect(PANEL_WRAPPER).not.toHaveClass(HIDDEN_CLASS); hidePanel(); expect(PANEL_EL).toExist(); expect(PANEL_WRAPPER).toHaveClass(HIDDEN_CLASS); showPanel(); expect(PANEL_EL).toExist(); expect(PANEL_WRAPPER).not.toHaveClass(HIDDEN_CLASS); }); it('destroy should clear the config locals on the panelRef', function () { openPanel(DEFAULT_CONFIG); expect(panelRef.config.locals).not.toEqual(null); panelRef.destroy(); expect(panelRef.config.locals).toEqual(null); }); it('destroy should destroy the panel scope', function () { openPanel(DEFAULT_CONFIG); expect(panelRef.config.scope.$$destroyed).toBe(false); panelRef.destroy(); expect(panelRef.config.scope.$$destroyed).toBe(true); }); describe('promises logic:', function() { var config; beforeEach(function() { config = { animation: $mdPanel.newPanelAnimation().withAnimation($mdPanel.animation.FADE) }; panelRef = $mdPanel.create(config); expect(panelRef.isAttached).toEqual(false); }); it('should resolve when opening/closing', function() { var openResolved = false; var closeResolved = false; expect(panelRef.id).toBeDefined(); expect(panelRef.open).toBeOfType('function'); expect(panelRef.close).toBeOfType('function'); panelRef.open().then(function() { openResolved = true; }); flushPanel(); expect(openResolved).toBe(true); expect(PANEL_WRAPPER).toExist(); expect(panelRef.panelContainer).not.toHaveClass(HIDDEN_CLASS); expect(panelRef.isAttached).toEqual(true); panelRef.close().then(function() { closeResolved = true; }); flushPanel(); expect(closeResolved).toBe(true); expect(panelRef.isAttached).toEqual(false); expect(PANEL_WRAPPER).not.toExist(); }); it('should reject on create when opening', function() { var openRejected = false; panelRef._createPanel = function() { return panelRef._$q.reject(); }; panelRef.open().catch(function() { openRejected = true; }); flushPanel(); expect(openRejected).toBe(true); expect(panelRef.isAttached).toEqual(false); }); it('should reject on attach when opening', function() { var openRejected = false; panelRef.attach = function() { return panelRef._$q.reject(); }; panelRef.open().catch(function() { openRejected = true; }); flushPanel(); expect(openRejected).toBe(true); expect(panelRef.isAttached).toEqual(false); }); it('should resolve on animate failure when opening', function() { var openResolved = false; panelRef.config.animation.animateOpen = function() { return panelRef._$q.reject(); }; panelRef.open().then(function() { openResolved = true; }); flushPanel(); expect(openResolved).toBe(true); expect(panelRef.isAttached).toEqual(true); expect(panelRef.panelContainer).not.toHaveClass(HIDDEN_CLASS); }); it('should reject on show when opening', function() { var openRejected = false; panelRef.show = function() { return panelRef._$q.reject(); }; panelRef.open().catch(function() { openRejected = true; }); flushPanel(); expect(openRejected).toBe(true); expect(panelRef.isAttached).toEqual(true); expect(panelRef.panelContainer).toHaveClass(HIDDEN_CLASS); }); it('should reject on hide when closing', function() { var closeRejected = false; openPanel(); expect(panelRef.panelContainer).not.toHaveClass(HIDDEN_CLASS); expect(panelRef.isAttached).toEqual(true); panelRef.hide = function() { return panelRef._$q.reject(); }; panelRef.close().catch(function() { closeRejected = true; }); flushPanel(); expect(closeRejected).toBe(true); expect(panelRef.isAttached).toEqual(true); }); it('should resolve on animate failure when closing', function() { var closeResolved = false; openPanel(); expect(panelRef.panelContainer).not.toHaveClass(HIDDEN_CLASS); expect(panelRef.isAttached).toEqual(true); panelRef.config.animation.animateClose = function() { return panelRef._$q.reject(); }; panelRef.close().then(function() { closeResolved = true; }); flushPanel(); expect(closeResolved).toBe(true); expect(panelRef.isAttached).toEqual(false); expect(panelRef.panelContainer).toHaveClass(HIDDEN_CLASS); }); it('should reject on detach when closing', function() { var closeRejected = false; openPanel(); expect(panelRef.panelContainer).not.toHaveClass(HIDDEN_CLASS); expect(panelRef.isAttached).toEqual(true); panelRef.detach = function() { return panelRef._$q.reject(); }; panelRef.close().catch(function() { closeRejected = true; }); flushPanel(); expect(closeRejected).toBe(true); expect(panelRef.isAttached).toEqual(true); }); it('should handle calling open multiple times', function() { var resolve1 = false; var resolve2 = false; var resolve3 = false; // Test twice in a row before flushing. panelRef.open().then(function() { resolve1 = true; }); panelRef.open().then(function() { resolve2 = true; }); flushPanel(); // Test again after a flush. panelRef.open().then(function() { resolve3 = true; }); flushPanel(); expect(resolve1).toBe(true); expect(resolve2).toBe(true); expect(resolve3).toBe(true); expect(panelRef.isAttached).toEqual(true); }); }); describe('config options:', function() { it('should not recreate a panel that is tracked by a user-defined id', function() { var config = { id: 'custom-id' }; var panel1 = $mdPanel.create(config); panel1.open(); flushPanel(); var panels = document.querySelectorAll(PANEL_EL); expect(panels.length).toEqual(1); var panel2 = $mdPanel.create(config); panel2.open(); flushPanel(); panels = document.querySelectorAll(PANEL_EL); expect(panels.length).toEqual(1); expect(panel1).toEqual(panel2); panel1.close(); }); it('should update the config of a panel that is tracked by a ' + 'user-defined id when attempting to create the panel more ' + 'than one time', function() { var config; config = { id: 'custom-id', panelClass: 'custom-class' }; openPanel(config); expect(panelRef.panelEl).toHaveClass('custom-class'); closePanel(); panelRef = undefined; config = { id: 'custom-id', panelClass: 'custom-class-2' }; openPanel(config); expect(panelRef.panelEl).toHaveClass('custom-class-2'); }); it('should allow multiple panels', function() { var customClass = 'custom-class'; var config1 = { panelClass: customClass, template: DEFAULT_TEMPLATE }; var panel1 = $mdPanel.create(config1); var panel2 = $mdPanel.create(DEFAULT_CONFIG); panel1.open(); panel2.open(); flushPanel(); var panels = document.querySelectorAll(PANEL_EL); expect(panels[0]).toHaveClass(customClass); expect(panels[1]).not.toHaveClass(customClass); panel1.close(); panel2.close(); }); describe('should attach panel to a specific element', function() { var parentEl; beforeEach(function() { parentEl = document.createElement('div'); parentEl.id = 'parent'; attachToBody(parentEl); }); it('using an Element', function() { var config = { attachTo: parentEl, template: DEFAULT_TEMPLATE }; openPanel(config); var panelWrapperEl = document.querySelector(PANEL_WRAPPER); expect(panelWrapperEl.parentElement).toBe(parentEl); closePanel(); expect(parentEl.childElementCount).toEqual(0); }); it('using an JQLite Object', function() { var config = { attachTo: angular.element(parentEl), template: DEFAULT_TEMPLATE }; openPanel(config); var panelWrapperEl = document.querySelector(PANEL_WRAPPER); expect(panelWrapperEl.parentElement).toBe(parentEl); closePanel(); expect(parentEl.childElementCount).toEqual(0); }); it('using a query selector', function() { var config = { attachTo: '#parent', template: DEFAULT_TEMPLATE }; openPanel(config); var panelWrapperEl = document.querySelector(PANEL_WRAPPER); expect(panelWrapperEl.parentElement).toBe(parentEl); closePanel(); expect(parentEl.childElementCount).toEqual(0); }); }); describe('should cause the propagation of events', function() { var config, wrapper; it('to be stopped when propagateContainerEvents=false', function() { config = { propagateContainerEvents: false, template: DEFAULT_TEMPLATE }; openPanel(config); wrapper = angular.element(document.querySelector(PANEL_WRAPPER)); expect(wrapper.css('pointer-events')).not.toEqual('none'); }); it('to NOT be stopped when propagateContainerEvents=true', function() { config = { propagateContainerEvents: true, template: DEFAULT_TEMPLATE }; openPanel(config); wrapper = angular.element(document.querySelector(PANEL_WRAPPER)); expect(wrapper.css('pointer-events')).toEqual('none'); }); }); it('should apply a custom css class to the panel', function() { var customClass = 'custom-class'; var config = { panelClass: customClass, template: DEFAULT_TEMPLATE }; openPanel(config); expect('.custom-class').toExist(); expect(PANEL_EL).toHaveClass(customClass); }); it('should set the z-index on the panel-container', function() { var zIndex = '150'; var config = { template: DEFAULT_TEMPLATE, zIndex: zIndex }; openPanel(config); // We have to use `toMatch` here, because IE11 is sometimes returning an integer instead of // an string. expect(document.querySelector(PANEL_WRAPPER).style.zIndex) .toMatch(zIndex); }); it('should set z-index to 0', function() { var zIndex = '0'; var config = { template: DEFAULT_TEMPLATE, zIndex: zIndex }; openPanel(config); // We have to use `toMatch` here, because IE11 is sometimes returning an integer instead of // an string. expect(document.querySelector(PANEL_WRAPPER).style.zIndex) .toMatch(zIndex); }); it('should not close when clickOutsideToClose set to false', function() { openPanel(); clickPanelContainer(); expect(PANEL_EL).toExist(); }); it('should close when clickOutsideToClose set to true', function() { var config = { clickOutsideToClose: true }; openPanel(config); clickPanelContainer(); // TODO(ErinCoughlan) - Add this when destroy is added. // expect(panelRef).toBeUndefined(); expect(PANEL_EL).not.toExist(); }); it('should close when clickOutsideToClose set to true and ' + 'propagateContainerEvents is also set to true', function() { var config = { propagateContainerEvents: true, clickOutsideToClose: true }; openPanel(config); clickPanelContainer(getElement('body')); expect(PANEL_EL).not.toExist(); }); it('should not close when escapeToClose set to false', function() { openPanel(); pressEscape(); expect(PANEL_EL).toExist(); }); it('should close when escapeToClose set to true', function() { var config = { escapeToClose: true }; openPanel(config); pressEscape(); // TODO(ErinCoughlan) - Add this when destroy is added. // expect(panelRef).toBeUndefined(); expect(PANEL_EL).not.toExist(); }); it('should call onCloseSuccess if provided after the panel finishes ' + 'closing', function() { var closeReason, closePanelRef; var onCloseSuccessCalled = false; var onCloseSuccess = function(panelRef, reason) { closePanelRef = panelRef; closeReason = reason; onCloseSuccessCalled = true; return $q.when(this); }; var config = angular.extend( {'onCloseSuccess': onCloseSuccess }, DEFAULT_CONFIG); openPanel(config); closePanel(); expect(onCloseSuccessCalled).toBe(true); expect(closeReason).toBe(undefined); expect(closePanelRef).toBe(panelRef); }); it('should call onCloseSuccess with "clickOutsideToClose" if close ' + 'is triggered by clicking on the panel container', function() { var closeReason, closePanelRef; var onCloseSuccessCalled = false; var onCloseSuccess = function(panelRef, reason) { closePanelRef = panelRef; closeReason = reason; onCloseSuccessCalled = true; return $q.when(this); }; var config = angular.extend( {'onCloseSuccess': onCloseSuccess, clickOutsideToClose: true, }, DEFAULT_CONFIG); openPanel(config); clickPanelContainer(); expect(onCloseSuccessCalled).toBe(true); expect(closeReason).toBe($mdPanel.closeReasons.CLICK_OUTSIDE); expect(closePanelRef).toBe(panelRef); }); it('should call onCloseSuccess with "escapeToClose" if close ' + 'is triggered by pressing escape', function() { var closePanelRef, closeReason; var onCloseSuccessCalled = false; var onCloseSuccess = function(panelRef, reason) { closePanelRef = panelRef; closeReason = reason; onCloseSuccessCalled = true; return $q.when(this); }; var config = angular.extend( {'onCloseSuccess': onCloseSuccess, escapeToClose: true }, DEFAULT_CONFIG); openPanel(config); pressEscape(); expect(onCloseSuccessCalled).toBe(true); expect(closeReason).toBe($mdPanel.closeReasons.ESCAPE); expect(closePanelRef).toBe(panelRef); }); it('should create and cleanup focus traps', function() { var config = { template: DEFAULT_TEMPLATE, trapFocus: true }; openPanel(config); // It should add two focus traps to the document around the panel content. var focusTraps = document.querySelectorAll(FOCUS_TRAPS_CLASS); expect(focusTraps.length).toBe(2); var topTrap = focusTraps[0]; var bottomTrap = focusTraps[1]; var panel = panelRef.panelEl; var isPanelFocused = false; panel[0].addEventListener('focus', function() { isPanelFocused = true; }); // Both of the focus traps should be in the normal tab order. expect(topTrap.tabIndex).toBe(0); expect(bottomTrap.tabIndex).toBe(0); // TODO(KarenParker): Find a way to test that focusing the traps redirects focus to the // md-dialog element. Firefox is problematic here, as calling element.focus() inside of // a focus event listener seems not to immediately update the document.activeElement. // This is a behavior better captured by an e2e test. closePanel(); // All of the focus traps should be removed when the dialog is closed. focusTraps = document.querySelectorAll(FOCUS_TRAPS_CLASS); expect(focusTraps.length).toBe(0); }); it('should not create focus traps when trapFocus=false', function() { openPanel(DEFAULT_CONFIG); // It should add two focus traps to the document around the panel content. var focusTraps = document.querySelectorAll(FOCUS_TRAPS_CLASS); expect(focusTraps.length).toBe(0); }); it('should focus on open', function() { var template = '<button id="donuts" md-autofocus>Donuts</button>'; var config = { template: template }; openPanel(config); expect(angular.element(document.activeElement).attr('id')).toBe('donuts'); }); it('should not focus on open when focusOnOpen=false', function() { var template = '<button id="donuts" md-autofocus>Donuts</button>'; var config = { focusOnOpen: false, template: template }; openPanel(config); expect(angular.element(document.activeElement).attr('id')).not.toBe('donuts'); }); it('should not be fullscreen by default', function() { openPanel(); expect(PANEL_EL).not.toHaveClass(FULLSCREEN_CLASS); }); it('should be fullscreen when fullscreen=true', function() { var config = { fullscreen: true }; openPanel(config); expect(PANEL_EL).toHaveClass(FULLSCREEN_CLASS); }); it('should default backdrop to false', function() { openPanel(DEFAULT_CONFIG); expect(BACKDROP_CLASS).not.toExist(); }); it('should show backdrop when hasBackdrop=true', function() { var config = { template: DEFAULT_TEMPLATE, hasBackdrop: true }; openPanel(config); expect(BACKDROP_CLASS).toExist(); closePanel(); expect(BACKDROP_CLASS).not.toExist(); }); it('should close when clickOutsideToClose and hasBackdrop are set to true', function() { var config = { template: DEFAULT_TEMPLATE, clickOutsideToClose: true, hasBackdrop: true }; openPanel(config); expect(PANEL_EL).toExist(); expect(BACKDROP_CLASS).toExist(); // Can't access the closePromise so mock it out. var closeCalled = false; panelRef.close = function() { closeCalled = true; return panelRef._$q.when(self); }; clickPanelContainer(); expect(closeCalled).toBe(true); }); it('should disable scrolling when disableParentScroll is true', function() { var config = { template: DEFAULT_TEMPLATE, disableParentScroll: true, }; spyOn($mdUtil, 'disableScrollAround').and.callThrough(); openPanel(config); expect(PANEL_EL).toExist(); expect(SCROLL_MASK_CLASS).not.toExist(); closePanel(); expect($mdUtil.disableScrollAround).toHaveBeenCalled(); }); describe('animation hooks: ', function() { it('should call onDomAdded if provided when adding the panel to the DOM', function() { var onDomAddedCalled = false; var onDomAdded = function() { onDomAddedCalled = true; return $q.when(this); }; var config = angular.extend( {'onDomAdded': onDomAdded}, DEFAULT_CONFIG); panelRef = $mdPanel.create(config); panelRef.attach(); flushPanel(); expect(onDomAddedCalled).toBe(true); expect(PANEL_EL).toExist(); expect(PANEL_WRAPPER).toHaveClass(HIDDEN_CLASS); }); it('should continue resolving when onDomAdded resolves', function() { var attachResolved = false; var onDomAddedCalled = false; var onDomAdded = function() { onDomAddedCalled = true; return $q.when(this); }; var config = angular.extend( {'onDomAdded': onDomAdded}, DEFAULT_CONFIG); expect(PANEL_EL).not.toExist(); panelRef = $mdPanel.create(config); panelRef.open().then(function() { attachResolved = true; }); flushPanel(); expect(onDomAddedCalled).toBe(true); expect(PANEL_EL).toExist(); expect(attachResolved).toBe(true); expect(panelRef.isAttached).toEqual(true); expect(panelRef.panelContainer).not.toHaveClass(HIDDEN_CLASS); }); it('should reject open when onDomAdded rejects', function() { var openRejected = false; var onDomAddedCalled = false; var onDomAdded = function() { onDomAddedCalled = true; return $q.reject(); }; var config = angular.extend( {'onDomAdded': onDomAdded}, DEFAULT_CONFIG); panelRef = $mdPanel.create(config); panelRef.open().catch(function() { openRejected = true; }); flushPanel(); expect(onDomAddedCalled).toBe(true); expect(openRejected).toBe(true); expect(panelRef.isAttached).toEqual(true); expect(panelRef.panelContainer).toHaveClass(HIDDEN_CLASS); }); it('should call onOpenComplete if provided after adding the panel to the ' + 'DOM and animating', function() { var onOpenCompleteCalled = false; var onOpenComplete = function() { onOpenCompleteCalled = true; return $q.when(this); }; var config = angular.extend( {'onOpenComplete': onOpenComplete}, DEFAULT_CONFIG); openPanel(config); expect(onOpenCompleteCalled).toBe(true); expect(PANEL_EL).toExist(); expect(PANEL_WRAPPER).not.toHaveClass(HIDDEN_CLASS); }); it('should call onRemoving if provided after hiding the panel but before ' + 'the panel is removed', function() { var onRemovingCalled = false; var onDomRemovedCalled = false; var onRemoving = function() { onRemovingCalled = true; return $q.when(this); }; var onDomRemoved = function() { onDomRemovedCalled = true; return $q.when(this); }; var config = angular.extend({'onRemoving': onRemoving, 'onDomRemoved': onDomRemoved}, DEFAULT_CONFIG); openPanel(config); hidePanel(); expect(onRemovingCalled).toBe(true); expect(onDomRemovedCalled).toBe(false); expect(PANEL_EL).toExist(); }); it('should continue resolving when onRemoving resolves', function() { var hideResolved = false; var onRemovingCalled = false; var onRemoving = function() { onRemovingCalled = true; return $q.when(this); }; var config = angular.extend({'onRemoving': onRemoving}, DEFAULT_CONFIG); openPanel(config); panelRef.hide().then(function() { hideResolved = true; }); flushPanel(); expect(onRemovingCalled).toBe(true); expect(PANEL_EL).toExist(); expect(hideResolved).toBe(true); expect(PANEL_WRAPPER).toHaveClass(HIDDEN_CLASS); }); it('should reject hide when onRemoving rejects', function() { var hideRejected = false; var onRemoving = function() { return $q.reject(); }; var config = angular.extend( {'onRemoving': onRemoving}, DEFAULT_CONFIG); openPanel(config); panelRef.hide().catch(function() { hideRejected = true; }); flushPanel(); expect(hideRejected).toBe(true); expect(PANEL_EL).toExist(); expect(PANEL_WRAPPER).not.toHaveClass(HIDDEN_CLASS); }); it('should call onRemoving on escapeToClose', function() { var onRemovingCalled = false; var onRemoving = function() { onRemovingCalled = true; return $q.when(this); }; var config = angular.extend({ 'onRemoving': onRemoving, escapeToClose: true}, DEFAULT_CONFIG); openPanel(config); pressEscape(); expect(PANEL_EL).not.toExist(); expect(onRemovingCalled).toBe(true); }); it('should call onRemoving on clickOutsideToClose', function() { var onRemovingCalled = false; var onRemoving = function() { onRemovingCalled = true; return $q.when(this); }; var config = angular.extend({ 'onRemoving': onRemoving, clickOutsideToClose: true}, DEFAULT_CONFIG); openPanel(config); clickPanelContainer(); expect(PANEL_EL).not.toExist(); expect(onRemovingCalled).toBe(true); }); it('should call onDomRemoved if provided when removing the panel from ' + 'the DOM', function() { var onDomRemovedCalled = false; var onDomRemoved = function() { onDomRemovedCalled = true; return $q.when(this); }; var config = angular.extend( {'onDomRemoved': onDomRemoved}, DEFAULT_CONFIG); openPanel(config); closePanel(); expect(onDomRemovedCalled).toBe(true); expect(PANEL_EL).not.toExist(); }); it('should call onDomRemoved on escapeToClose', function() { var onDomRemovedCalled = false; var onDomRemoved = function() { onDomRemovedCalled = true; return $q.when(this); }; var config = angular.extend({ 'onDomRemoved': onDomRemoved, escapeToClose: true}, DEFAULT_CONFIG); openPanel(config); pressEscape(); expect(PANEL_EL).not.toExist(); expect(onDomRemovedCalled).toBe(true); }); it('should call onDomRemoved on clickOutsideToClose', function() { var onDomRemovedCalled = false; var onDomRemoved = function() { onDomRemovedCalled = true; return $q.when(this); }; var config = angular.extend({ 'onDomRemoved': onDomRemoved, clickOutsideToClose: true}, DEFAULT_CONFIG); openPanel(config); clickPanelContainer(); expect(PANEL_EL).not.toExist(); expect(onDomRemovedCalled).toBe(true); }); }); describe('CSS class logic:', function() { it('should add a class to the container/wrapper', function() { openPanel(DEFAULT_CONFIG); panelRef.panelContainer.addClass('my-class'); expect(PANEL_WRAPPER).toHaveClass('my-class'); expect(PANEL_EL).not.toHaveClass('my-class'); }); it('should add a class to the element', function() { openPanel(DEFAULT_CONFIG); panelRef.panelEl.addClass('my-class'); expect(PANEL_WRAPPER).not.toHaveClass('my-class'); expect(PANEL_EL).toHaveClass('my-class'); }); it('should remove a class from the container/wrapper', function() { openPanel(DEFAULT_CONFIG); panelRef.panelContainer.addClass('my-class'); expect(PANEL_WRAPPER).toHaveClass('my-class'); expect(PANEL_EL).not.toHaveClass('my-class'); panelRef.panelContainer.removeClass('my-class'); expect(PANEL_WRAPPER).not.toHaveClass('my-class'); expect(PANEL_EL).not.toHaveClass('my-class'); }); it('should remove a class from the element', function() { openPanel(DEFAULT_CONFIG); panelRef.panelEl.addClass('my-class'); expect(PANEL_WRAPPER).not.toHaveClass('my-class'); expect(PANEL_EL).toHaveClass('my-class'); panelRef.panelEl.removeClass('my-class'); expect(PANEL_WRAPPER).not.toHaveClass('my-class'); expect(PANEL_EL).not.toHaveClass('my-class'); }); it('should toggle a class on the container/wrapper', function() { openPanel(DEFAULT_CONFIG); panelRef.panelContainer.toggleClass('my-class'); expect(PANEL_WRAPPER).toHaveClass('my-class'); expect(PANEL_EL).not.toHaveClass('my-class'); panelRef.panelContainer.toggleClass('my-class'); expect(PANEL_WRAPPER).not.toHaveClass('my-class'); expect(PANEL_EL).not.toHaveClass('my-class'); }); it('should toggle a class on the element', function() { openPanel(DEFAULT_CONFIG); panelRef.panelEl.toggleClass('my-class'); expect(PANEL_WRAPPER).not.toHaveClass('my-class'); expect(PANEL_EL).toHaveClass('my-class'); panelRef.panelEl.toggleClass('my-class'); expect(PANEL_WRAPPER).not.toHaveClass('my-class'); expect(PANEL_EL).not.toHaveClass('n-class'); }); }); describe('should focus on the origin element on', function() { var myButton; var detachFocusConfig; beforeEach(function() { attachToBody('<button id="donuts">Donuts</button>'); myButton = angular.element(document.querySelector('#donuts')); detachFocusConfig = angular.extend({ origin: '#donuts' }, DEFAULT_CONFIG); }); it('hide when provided', function () { openPanel(detachFocusConfig); expect(myButton).not.toBeFocused(); hidePanel(); expect(myButton).toBeFocused(); }); it('close when provided', function () { openPanel(detachFocusConfig); expect(myButton).not.toBeFocused(); closePanel(); expect(myButton).toBeFocused(); }); it('clickOutsideToClose', function() { detachFocusConfig.clickOutsideToClose = true; openPanel(detachFocusConfig); expect(myButton).not.toBeFocused(); clickPanelContainer(); expect(myButton).toBeFocused(); }); it('escapeToClose', function() { detachFocusConfig.escapeToClose = true; openPanel(detachFocusConfig); expect(myButton).not.toBeFocused(); pressEscape(); expect(myButton).toBeFocused(); }); }); }); describe('grouping logic:', function() { it('should create a group using the newPanelGroup method', function() { $mdPanel.newPanelGroup('test'); expect($mdPanel._groups['test']).toExist(); }); it('should create a group using the config option groupName when the ' + 'group hasn\'t been created yet', function() { var config = { groupName: 'test' }; var panel = $mdPanel.create(config); expect($mdPanel._groups['test']).toExist(); }); it('should create multiple groups if an array is given for the config ' + 'option groupName', function() { var config = { groupName: ['test1', 'test2'] }; var panel = $mdPanel.create(config); expect($mdPanel._groups['test1']).toExist(); expect($mdPanel._groups['test2']).toExist(); }); it('should only create a group once', function() { var config = { groupName: 'test' }; var panel = $mdPanel.create(config); expect(getNumberOfGroups()).toEqual(1); $mdPanel.newPanelGroup('test'); expect(getNumberOfGroups()).toEqual(1); }); it('should not create a group using the config option when the group is ' + 'already defined', function() { $mdPanel.newPanelGroup('test'); expect(getNumberOfGroups()).toEqual(1); var config = { groupName: 'test' }; var panel = $mdPanel.create(config); expect(getNumberOfGroups()).toEqual(1); }); it('should add a panel to a group using the addToGroup method', function() { $mdPanel.newPanelGroup('test'); var panel = $mdPanel.create(DEFAULT_CONFIG); panel.addToGroup('test'); expect(getGroupPanels('test')).toContain(panel); }); it('should add a panel to a group using the config option groupName', function() { $mdPanel.newPanelGroup('test'); var config = { groupName: 'test' }; var panel = $mdPanel.create(config); expect(getGroupPanels('test')).toContain(panel); }); it('should add a panel to multiple groups when an array is given for the ' + 'config option groupName', function() { $mdPanel.newPanelGroup('test1'); $mdPanel.newPanelGroup('test2'); var config = { groupName: ['test1', 'test2'] }; var panel = $mdPanel.create(config); expect(getGroupPanels('test1')).toContain(panel); expect(getGroupPanels('test2')).toContain(panel); }); it('should remove a panel from a group using the removeFromGroup method', function() { $mdPanel.newPanelGroup('test'); var config = { groupName: 'test' }; var panel = $mdPanel.create(config); panel.removeFromGroup('test'); expect(getGroupPanels('test')).not.toContain(panel); }); it('should not remove a panel from every group that it is in using the ' + 'removeFromGroup method and only requesting one of the panel\'s ' + 'groups', function() { $mdPanel.newPanelGroup('test1'); $mdPanel.newPanelGroup('test2'); var config = { groupName: ['test1', 'test2'] }; var panel = $mdPanel.create(config); panel.removeFromGroup('test1'); expect(getGroupPanels('test1')).not.toContain(panel); expect(getGroupPanels('test2')).toContain(panel); }); it('should remove a panel from a group on panel destroy', function() { $mdPanel.newPanelGroup('test'); var config = { groupName: 'test' }; var panel = $mdPanel.create(config); panel.destroy(); expect(getGroupPanels('test')).not.toContain(panel); }); it('should remove a panel from all of its groups on panel destroy', function() { $mdPanel.newPanelGroup('test1'); $mdPanel.newPanelGroup('test2'); var config = { groupName: ['test1', 'test2'] }; var panel = $mdPanel.create(config); panel.destroy(); expect(getGroupPanels('test1')).not.toContain(panel); expect(getGroupPanels('test2')).not.toContain(panel); }); it('should set the maximum number of panels allowed open within a group ' + 'using the newPanelGroup option', function() { $mdPanel.newPanelGroup('test', { maxOpen: 1 }); expect(getGroupMaxOpen('test')).toEqual(1); }); it('should set the maximum number of panels allowed open within a group ' + 'using the setGroupMaxOpen method', function() { $mdPanel.newPanelGroup('test'); $mdPanel.setGroupMaxOpen('test', 1); expect(getGroupMaxOpen('test')).toEqual(1); }); it('should throw if trying to set maxOpen on a group that doesn\'t exist', function() { var expression = function() { $mdPanel.setGroupMaxOpen('test', 1); }; expect(expression).toThrow(); }); it('should update open panels when a panel is closed', function() { $mdPanel.newPanelGroup('test'); var config = { groupName: 'test' }; openPanel(config); flushPanel(); expect(getGroupOpenPanels('test')).toContain(panelRef); closePanel(); expect(getGroupOpenPanels('test')).not.toContain(panelRef); }); it('should update open panels of all of the panel\'s groups when a panel ' + 'is closed', function() { $mdPanel.newPanelGroup('test1'); $mdPanel.newPanelGroup('test2'); var config = { groupName: ['test1', 'test2'] }; openPanel(config); flushPanel(); expect(getGroupOpenPanels('test1')).toContain(panelRef); expect(getGroupOpenPanels('test2')).toContain(panelRef); closePanel(); expect(getGroupOpenPanels('test1')).not.toContain(panelRef); expect(getGroupOpenPanels('test2')).not.toContain(panelRef); }); it('should close the first open panel when more than the maximum number ' + 'of panels is opened', function() { $mdPanel.newPanelGroup('test', { maxOpen: 2 }); var config = { groupName: 'test' }; var panel1 = $mdPanel.create(config); var panel2 = $mdPanel.create(config); var panel3 = $mdPanel.create(config); panel1.open(); flushPanel(); expect(panel1.isAttached).toEqual(true); panel2.open(); panel3.open(); flushPanel(); expect(panel1.isAttached).toEqual(false); expect(panel2.isAttached).toEqual(true); expect(panel3.isAttached).toEqual(true); panel2.close(); panel3.close(); }); it('should close the first open panel of any group that the panel is in ' + 'when more than the maxium number of panels is opened', function() { $mdPanel.newPanelGroup('groupWithMaxOpen1', { maxOpen: 1 }); $mdPanel.newPanelGroup('groupWithMaxOpen2', { maxOpen: 2 }); var config1 = { groupName: 'groupWithMaxOpen1' }; var config2 = { groupName: 'groupWithMaxOpen2' }; var config3 = { groupName: ['groupWithMaxOpen1', 'groupWithMaxOpen2'] }; var panelInGroupWithMaxOpen1 = $mdPanel.create(config1); var panelInBothGroups = $mdPanel.create(config3); var panelInGroupWithMaxOpen2 = $mdPanel.create(config2); var panel2InGroupWithMaxOpen2 = $mdPanel.create(config2); panelInGroupWithMaxOpen1.open(); flushPanel(); expect(panelInGroupWithMaxOpen1.isAttached).toEqual(true); expect(getGroupOpenPanels('groupWithMaxOpen1')) .toContain(panelInGroupWithMaxOpen1); panelInBothGroups.open(); flushPanel(); expect(panelInGroupWithMaxOpen1.isAttached).toEqual(false); expect(panelInBothGroups.isAttached).toEqual(true); expect(getGroupOpenPanels('groupWithMaxOpen1')) .not.toContain(panelInGroupWithMaxOpen1); expect(getGroupOpenPanels('groupWithMaxOpen1')) .toContain(panelInBothGroups); expect(getGroupOpenPanels('groupWithMaxOpen2')) .toContain(panelInBothGroups); panelInGroupWithMaxOpen2.open(); panel2InGroupWithMaxOpen2.open(); flushPanel(); expect(panelInBothGroups.isAttached).toEqual(false); expect(panelInGroupWithMaxOpen2.isAttached).toEqual(true); expect(panel2InGroupWithMaxOpen2.isAttached).toEqual(true); expect(getGroupOpenPanels('groupWithMaxOpen2')) .not.toContain(panelInBothGroups); expect(getGroupOpenPanels('groupWithMaxOpen2')) .toContain(panelInGroupWithMaxOpen2); expect(getGroupOpenPanels('groupWithMaxOpen2')) .toContain(panel2InGroupWithMaxOpen2); panelInGroupWithMaxOpen2.close(); panel2InGroupWithMaxOpen2.close(); }); }); describe('component logic: ', function() { it('should allow templateUrl to specify content', function() { var htmlContent = 'Puppies and Unicorns'; var template = '<div>' + htmlContent + '</div>'; $templateCache.put('template.html', template); var config = { templateUrl: 'template.html' }; openPanel(config); expect(PANEL_EL).toContainHtml(htmlContent); }); it('should allow template to specify content', function() { var htmlContent = 'Ice cream'; var template = '<div>' + htmlContent + '</div>'; var config = { template: template }; openPanel(config); expect(PANEL_EL).toContainHtml(htmlContent); }); it('should allow a controller to be specified', function() { var htmlContent = 'Cotton candy'; var template = '<div>{{ content }}</div>'; var config = { template: template, controller: function Ctrl($scope) { $scope['content'] = htmlContent; } }; openPanel(config); expect(PANEL_EL).toContainHtml(htmlContent); }); it('should allow controllerAs syntax', function() { var htmlContent = 'Cupcakes'; var template = '<div>{{ ctrl.content }}</div>'; var config = { template: template, controller: function Ctrl() { this.content = htmlContent; }, controllerAs: 'ctrl' }; openPanel(config); expect(PANEL_EL).toContainHtml(htmlContent); }); it('should wait for resolve before creating the panel', function() { var htmlContent = 'Cheesecake'; var template = '<div>{{ ctrl.content }}</div>'; var deferred = $q.defer(); var config = { template: template, controller: function Ctrl(content) { this.content = content; }, controllerAs: 'ctrl', resolve: { content: function() { return deferred.promise.then(function(content) { return content; }); } } }; openPanel(config); expect(PANEL_EL).not.toExist(); deferred.resolve(htmlContent); flushPanel(); expect(PANEL_EL).toExist(); expect(PANEL_EL).toContainHtml(htmlContent); }); it('should bind resolve to the controller', function() { var htmlContent = 'Gummy bears'; var template = '<div>{{ ctrl.content }}</div>'; var config = { template: template, controller: function Ctrl() { this.content; // Populated via bindToController. }, controllerAs: 'ctrl', resolve: { content: function($q) { return $q.when(htmlContent); } } }; openPanel(config); expect(PANEL_EL).toContainHtml(htmlContent); }); it('should allow locals to be injected in the controller', function() { var htmlContent = 'Tiramisu'; var template = '<div>{{ ctrl.content }} {{ ctrl.myPanel.id }}</div>'; var config = { template: template, controller: function Ctrl(content, mdPanelRef) { this.content = content; this.myPanel = mdPanelRef; }, controllerAs: 'ctrl', locals: { content: htmlContent }, bindToController: false, }; openPanel(config); expect(PANEL_EL).toContainHtml(htmlContent); expect(PANEL_EL).toContainHtml(PANEL_ID_PREFIX); }); it('should bind locals to the controller', function() { var htmlContent = 'Apple Pie'; var template = '<div>{{ ctrl.content }} {{ ctrl.mdPanelRef.id }}</div>'; var config = { template: template, controller: function Ctrl() { this.content; // Populated via bindToController. this.mdPanelRef; }, controllerAs: 'ctrl', locals: { content: htmlContent } }; ope