// Copyright 2008 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. goog.provide('goog.ui.ControlTest'); goog.setTestOnly('goog.ui.ControlTest'); goog.require('goog.a11y.aria'); goog.require('goog.a11y.aria.State'); goog.require('goog.array'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); goog.require('goog.dom.classlist'); goog.require('goog.events'); goog.require('goog.events.BrowserEvent'); goog.require('goog.events.KeyCodes'); goog.require('goog.html.testing'); goog.require('goog.object'); goog.require('goog.string'); goog.require('goog.style'); goog.require('goog.testing.ExpectedFailures'); goog.require('goog.testing.events'); goog.require('goog.testing.events.Event'); goog.require('goog.testing.jsunit'); goog.require('goog.ui.Component'); goog.require('goog.ui.Control'); goog.require('goog.ui.ControlRenderer'); goog.require('goog.ui.registry'); goog.require('goog.userAgent'); // Disabled due to problems on farm. var testFocus = false; var control; var ALL_EVENTS = goog.object.getValues(goog.ui.Component.EventType); var events = {}; var expectedFailures; var sandbox; var aria = goog.a11y.aria; var State = goog.a11y.aria.State; function setUpPage() { expectedFailures = new goog.testing.ExpectedFailures(); sandbox = document.getElementById('sandbox'); } /** * A dummy renderer, for testing purposes. * @constructor * @extends {goog.ui.ControlRenderer} */ function TestRenderer() { goog.ui.ControlRenderer.call(this); } goog.inherits(TestRenderer, goog.ui.ControlRenderer); /** * Initializes the testcase prior to execution. */ function setUp() { control = new goog.ui.Control('Hello'); control.setDispatchTransitionEvents(goog.ui.Component.State.ALL, true); goog.events.listen(control, ALL_EVENTS, countEvent); } /** * Cleans up after executing the testcase. */ function tearDown() { control.dispose(); expectedFailures.handleTearDown(); goog.dom.removeChildren(sandbox); resetEventCount(); } /** * Resets the global counter for events dispatched by test objects. */ function resetEventCount() { goog.object.clear(events); } /** * Increments the global counter for events of this type. * @param {goog.events.Event} e Event to count. */ function countEvent(e) { var type = e.type; var target = e.target; if (!events[target]) { events[target] = {}; } if (events[target][type]) { events[target][type]++; } else { events[target][type] = 1; } } /** * Returns the number of times test objects dispatched events of the given * type since the global counter was last reset. * @param {goog.ui.Control} target Event target. * @param {string} type Event type. * @return {number} Number of events of this type. */ function getEventCount(target, type) { return events[target] && events[target][type] || 0; } /** * Returns true if no events were dispatched since the last reset. * @return {boolean} Whether no events have been dispatched since the last * reset. */ function noEventsDispatched() { return !events || goog.object.isEmpty(events); } /** * Returns the number of event listeners created by the control. * @param {goog.ui.Control} control Control whose event listers are to be * counted. * @return {number} Number of event listeners. */ function getListenerCount(control) { return control.googUiComponentHandler_ ? goog.object.getCount(control.getHandler().keys_) : 0; } /** * Simulates a mousedown event on the given element, including focusing it. * @param {Element} element Element on which to simulate mousedown. * @param {goog.events.BrowserEvent.MouseButton=} opt_button Mouse button; * defaults to {@code goog.events.BrowserEvent.MouseButton.LEFT}. * @return {boolean} Whether the event was allowed to proceed. */ function fireMouseDownAndFocus(element, opt_button) { var result = goog.testing.events.fireMouseDownEvent(element, opt_button); if (result) { // Browsers move focus for all buttons, not just the left button. element.focus(); } return result; } /** * @return {boolean} Whether we're on Mac Safari 3.x. */ function isMacSafari3() { return goog.userAgent.WEBKIT && goog.userAgent.MAC && !goog.userAgent.isVersionOrHigher('527'); } /** * Tests the {@link goog.ui.Control} constructor. */ function testConstructor() { assertNotNull('Constructed control must not be null', control); assertEquals( 'Content must have expected value', 'Hello', control.getContent()); assertEquals( 'Renderer must default to the registered renderer', goog.ui.registry.getDefaultRenderer(goog.ui.Control), control.getRenderer()); var content = goog.dom.createDom( goog.dom.TagName.DIV, null, 'Hello', goog.dom.createDom(goog.dom.TagName.B, null, 'World')); var testRenderer = new TestRenderer(); var fakeDomHelper = {}; var foo = new goog.ui.Control(content, testRenderer, fakeDomHelper); assertNotNull('Constructed object must not be null', foo); assertEquals('Content must have expected value', content, foo.getContent()); assertEquals( 'Renderer must have expected value', testRenderer, foo.getRenderer()); assertEquals( 'DOM helper must have expected value', fakeDomHelper, foo.getDomHelper()); foo.dispose(); } /** * Tests {@link goog.ui.Control#getHandler}. */ function testGetHandler() { assertUndefined( 'Event handler must be undefined before getHandler() ' + 'is called', control.googUiComponentHandler_); var handler = control.getHandler(); assertNotNull('Event handler must not be null', handler); assertEquals( 'getHandler() must return the same instance if called again', handler, control.getHandler()); } /** * Tests {@link goog.ui.Control#isHandleMouseEvents}. */ function testIsHandleMouseEvents() { assertTrue( 'Controls must handle their own mouse events by default', control.isHandleMouseEvents()); } /** * Tests {@link goog.ui.Control#setHandleMouseEvents}. */ function testSetHandleMouseEvents() { assertTrue( 'Control must handle its own mouse events by default', control.isHandleMouseEvents()); control.setHandleMouseEvents(false); assertFalse( 'Control must no longer handle its own mouse events', control.isHandleMouseEvents()); control.setHandleMouseEvents(true); assertTrue( 'Control must once again handle its own mouse events', control.isHandleMouseEvents()); control.render(sandbox); assertTrue( 'Rendered control must handle its own mouse events', control.isHandleMouseEvents()); control.setHandleMouseEvents(false); assertFalse( 'Rendered control must no longer handle its own mouse events', control.isHandleMouseEvents()); control.setHandleMouseEvents(true); assertTrue( 'Rendered control must once again handle its own mouse events', control.isHandleMouseEvents()); } /** * Tests {@link goog.ui.Control#getKeyEventTarget}. */ function testGetKeyEventTarget() { assertNull( 'Key event target of control without DOM must be null', control.getKeyEventTarget()); control.createDom(); assertEquals( 'Key event target of control with DOM must be its element', control.getElement(), control.getKeyEventTarget()); } /** * Tests {@link goog.ui.Control#getKeyHandler}. */ function testGetKeyHandler() { assertUndefined( 'Key handler must be undefined before getKeyHandler() ' + 'is called', control.keyHandler_); var keyHandler = control.getKeyHandler(); assertNotNull('Key handler must not be null', keyHandler); assertEquals( 'getKeyHandler() must return the same instance if called ' + 'again', keyHandler, control.getKeyHandler()); } /** * Tests {@link goog.ui.Control#getRenderer}. */ function testGetRenderer() { assertEquals( 'Renderer must be the default registered renderer', goog.ui.registry.getDefaultRenderer(goog.ui.Control), control.getRenderer()); } /** * Tests {@link goog.ui.Control#setRenderer}. */ function testSetRenderer() { control.createDom(); assertNotNull('Control must have a DOM', control.getElement()); assertFalse('Control must not be in the document', control.isInDocument()); assertEquals( 'Renderer must be the default registered renderer', goog.ui.registry.getDefaultRenderer(goog.ui.Control), control.getRenderer()); var testRenderer = new TestRenderer(); control.setRenderer(testRenderer); assertNull( 'Control must not have a DOM after its renderer is reset', control.getElement()); assertFalse( 'Control still must not be in the document', control.isInDocument()); assertEquals( 'Renderer must have expected value', testRenderer, control.getRenderer()); control.render(sandbox); assertTrue('Control must be in the document', control.isInDocument()); assertThrows( 'Resetting the renderer after the control has entered ' + 'the document must throw error', function() { control.setRenderer({}); }); } /** * Tests {@link goog.ui.Control#getExtraClassNames}. */ function testGetExtraClassNames() { assertNull( 'Control must not have any extra class names by default', control.getExtraClassNames()); } /** * Tests {@link goog.ui.Control#addExtraClassName} and * {@link goog.ui.Control#removeExtraClassName}. */ function testAddRemoveClassName() { assertNull( 'Control must not have any extra class names by default', control.getExtraClassNames()); control.addClassName('foo'); assertArrayEquals( 'Control must have expected extra class names', ['foo'], control.getExtraClassNames()); assertNull('Control must not have a DOM', control.getElement()); control.createDom(); assertSameElements( 'Control\'s element must have expected class names', ['goog-control', 'foo'], goog.dom.classlist.get(control.getElement())); control.addClassName('bar'); assertArrayEquals( 'Control must have expected extra class names', ['foo', 'bar'], control.getExtraClassNames()); assertSameElements( 'Control\'s element must have expected class names', ['goog-control', 'foo', 'bar'], goog.dom.classlist.get(control.getElement())); control.addClassName('bar'); assertArrayEquals( 'Adding the same class name again must be a no-op', ['foo', 'bar'], control.getExtraClassNames()); assertSameElements( 'Adding the same class name again must be a no-op', ['goog-control', 'foo', 'bar'], goog.dom.classlist.get(control.getElement())); control.addClassName(null); assertArrayEquals( 'Adding null class name must be a no-op', ['foo', 'bar'], control.getExtraClassNames()); assertSameElements( 'Adding null class name must be a no-op', ['goog-control', 'foo', 'bar'], goog.dom.classlist.get(control.getElement())); control.removeClassName(null); assertArrayEquals( 'Removing null class name must be a no-op', ['foo', 'bar'], control.getExtraClassNames()); assertSameElements( 'Removing null class name must be a no-op', ['goog-control', 'foo', 'bar'], goog.dom.classlist.get(control.getElement())); control.removeClassName('foo'); assertArrayEquals( 'Control must have expected extra class names', ['bar'], control.getExtraClassNames()); assertSameElements( 'Control\'s element must have expected class names', ['goog-control', 'bar'], goog.dom.classlist.get(control.getElement())); control.removeClassName('bar'); assertNull( 'Control must not have any extra class names', control.getExtraClassNames()); assertSameElements( 'Control\'s element must have expected class names', ['goog-control'], goog.dom.classlist.get(control.getElement())); } /** * Tests {@link goog.ui.Control#enableClassName}. */ function testEnableClassName() { assertNull( 'Control must not have any extra class names by default', control.getExtraClassNames()); control.enableClassName('foo', true); assertArrayEquals( 'Control must have expected extra class names', ['foo'], control.getExtraClassNames()); control.enableClassName('bar', true); assertArrayEquals( 'Control must have expected extra class names', ['foo', 'bar'], control.getExtraClassNames()); control.enableClassName('bar', true); assertArrayEquals( 'Enabling the same class name again must be a no-op', ['foo', 'bar'], control.getExtraClassNames()); control.enableClassName(null); assertArrayEquals( 'Enabling null class name must be a no-op', ['foo', 'bar'], control.getExtraClassNames()); control.enableClassName('foo', false); assertArrayEquals( 'Control must have expected extra class names', ['bar'], control.getExtraClassNames()); control.enableClassName('bar', false); assertNull( 'Control must not have any extra class names', control.getExtraClassNames()); } /** * Tests {@link goog.ui.Control#createDom}. */ function testCreateDom() { assertNull('Control must not have a DOM by default', control.getElement()); assertFalse( 'Control must not allow text selection by default', control.isAllowTextSelection()); assertTrue('Control must be visible by default', control.isVisible()); control.createDom(); assertNotNull('Control must have a DOM', control.getElement()); assertTrue( 'Control\'s element must be unselectable', goog.style.isUnselectable(control.getElement())); assertTrue( 'Control\'s element must be visible', control.getElement().style.display != 'none'); control.setAllowTextSelection(true); control.createDom(); assertFalse( 'Control\'s element must be selectable', goog.style.isUnselectable(control.getElement())); control.setVisible(false); control.createDom(); assertTrue( 'Control\'s element must be hidden', control.getElement().style.display == 'none'); } /** * Tests {@link goog.ui.Control#getContentElement}. */ function testGetContentElement() { assertNull( 'Unrendered control must not have a content element', control.getContentElement()); control.createDom(); assertEquals( 'Control\'s content element must equal its root element', control.getElement(), control.getContentElement()); } /** * Tests {@link goog.ui.Control#canDecorate}. */ function testCanDecorate() { assertTrue(control.canDecorate(goog.dom.createElement(goog.dom.TagName.DIV))); } /** * Tests {@link goog.ui.Control#decorateInternal}. */ function testDecorateInternal() { sandbox.innerHTML = '
Hello, World!
'; var foo = goog.dom.getElement('foo'); control.decorate(foo); assertEquals( 'Decorated control\'s element must have expected value', foo, control.getElement()); assertTrue( 'Element must be unselectable', goog.style.isUnselectable(control.getElement())); assertTrue( 'Element must be visible', control.getElement().style.display != 'none'); } /** * Tests {@link goog.ui.Control#decorateInternal} with a control that * allows text selection. */ function testDecorateInternalForSelectableControl() { sandbox.innerHTML = '
Hello, World!
'; var foo = goog.dom.getElement('foo'); control.setAllowTextSelection(true); control.decorate(foo); assertEquals( 'Decorated control\'s element must have expected value', foo, control.getElement()); assertFalse( 'Element must be selectable', goog.style.isUnselectable(control.getElement())); assertTrue('Control must be visible', control.isVisible()); } /** * Tests {@link goog.ui.Control#decorateInternal} with a hidden element. */ function testDecorateInternalForHiddenElement() { sandbox.innerHTML = ''; var foo = goog.dom.getElement('foo'); control.decorate(foo); assertEquals( 'Decorated control\'s element must have expected value', foo, control.getElement()); assertTrue( 'Element must be unselectable', goog.style.isUnselectable(control.getElement())); assertFalse('Control must be hidden', control.isVisible()); } /** * Tests {@link goog.ui.Control#enterDocument}. */ function testEnterDocument() { control.render(sandbox); assertTrue('Control must be in the document', control.isInDocument()); if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher(9)) { assertEquals( 'Control must have 5 mouse & 3 key event listeners on IE8', 8, getListenerCount(control)); } else { assertEquals( 'Control must have 4 mouse and 3 key event listeners', 7, getListenerCount(control)); } assertEquals( 'Control\'s key event handler must be attached to its ' + 'key event target', control.getKeyEventTarget(), control.getKeyHandler().element_); } /** * Tests {@link goog.ui.Control#enterDocument} for a control that doesn't * handle mouse events. */ function testEnterDocumentForControlWithoutMouseHandling() { control.setHandleMouseEvents(false); control.render(sandbox); assertTrue('Control must be in the document', control.isInDocument()); assertEquals( 'Control must have 3 key event listeners', 3, getListenerCount(control)); assertEquals( 'Control\'s key event handler must be attached to its ' + 'key event target', control.getKeyEventTarget(), control.getKeyHandler().element_); } /** * Tests {@link goog.ui.Control#enterDocument} for a control that isn't * focusable. */ function testEnterDocumentForNonFocusableControl() { control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.render(sandbox); assertTrue('Control must be in the document', control.isInDocument()); if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher(9)) { assertEquals( 'Control must have 5 mouse event listeners on IE8', 5, getListenerCount(control)); } else { assertEquals( 'Control must have 4 mouse event listeners', 4, getListenerCount(control)); } assertUndefined( 'Control must not have a key event handler', control.keyHandler_); } /** * Tests {@link goog.ui.Control#enterDocument} for a control that doesn't * need to do any event handling. */ function testEnterDocumentForControlWithoutEventHandlers() { control.setHandleMouseEvents(false); control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.render(sandbox); assertTrue('Control must be in the document', control.isInDocument()); assertEquals( 'Control must have 0 event listeners', 0, getListenerCount(control)); assertUndefined( 'Control must not have an event handler', control.googUiComponentHandler_); assertUndefined( 'Control must not have a key event handler', control.keyHandler_); } /** * Tests {@link goog.ui.Control#exitDocument}. */ function testExitDocument() { control.render(sandbox); assertTrue('Control must be in the document', control.isInDocument()); if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher(9)) { assertEquals( 'Control must have 5 mouse & 3 key event listeners on IE8', 8, getListenerCount(control)); } else { assertEquals( 'Control must have 4 mouse and 3 key event listeners', 7, getListenerCount(control)); } assertEquals( 'Control\'s key event handler must be attached to its ' + 'key event target', control.getKeyEventTarget(), control.getKeyHandler().element_); // Expected to fail on Mac Safari prior to version 527. expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue( 'Control\'s element must support keyboard focus', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); } catch (e) { expectedFailures.handleException(e); } control.exitDocument(); assertFalse( 'Control must no longer be in the document', control.isInDocument()); assertEquals( 'Control must have no event listeners', 0, getListenerCount(control)); assertNull( 'Control\'s key event handler must be unattached', control.getKeyHandler().element_); assertFalse( 'Control\'s element must no longer support keyboard focus', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); } /** * Tests {@link goog.ui.Control#dispose}. */ function testDispose() { control.render(sandbox); var handler = control.getHandler(); var keyHandler = control.getKeyHandler(); control.dispose(); assertFalse( 'Control must no longer be in the document', control.isInDocument()); assertTrue('Control must have been disposed of', control.isDisposed()); assertUndefined('Renderer must have been deleted', control.getRenderer()); assertNull('Content must be nulled out', control.getContent()); assertTrue('Event handler must have been disposed of', handler.isDisposed()); assertUndefined( 'Event handler must have been deleted', control.googUiComponentHandler_); assertTrue('Key handler must have been disposed of', keyHandler.isDisposed()); assertUndefined('Key handler must have been deleted', control.keyHandler_); assertNull( 'Extra class names must have been nulled out', control.getExtraClassNames()); } /** * Tests {@link goog.ui.Control#getContent}. */ function testGetContent() { assertNull( 'Empty control must have null content', (new goog.ui.Control(null)).getContent()); assertEquals( 'Control must have expected content', 'Hello', control.getContent()); control.render(sandbox); assertEquals( 'Control must have expected content after rendering', 'Hello', control.getContent()); } /** * Tests {@link goog.ui.Control#getContent}. */ function testGetContentForDecoratedControl() { sandbox.innerHTML = '
\n' + '
Hello, world!
\n' + '
Foo
\n' + '
Hello, world!
\n'; var empty = new goog.ui.Control(null); empty.decorate(goog.dom.getElement('empty')); assertNull( 'Content of control decorating empty DIV must be null', empty.getContent()); empty.dispose(); var text = new goog.ui.Control(null); text.decorate(goog.dom.getElement('text')); assertEquals( 'Content of control decorating DIV with text contents ' + 'must be as expected', 'Hello, world!', text.getContent().nodeValue); text.dispose(); var element = new goog.ui.Control(null); element.decorate(goog.dom.getElement('element')); assertEquals( 'Content of control decorating DIV with element child ' + 'must be as expected', goog.dom.getElement('element').firstChild, element.getContent()); element.dispose(); var nodelist = new goog.ui.Control(null); nodelist.decorate(goog.dom.getElement('nodelist')); assertSameElements( 'Content of control decorating DIV with mixed ' + 'contents must be as expected', goog.dom.getElement('nodelist').childNodes, nodelist.getContent()); nodelist.dispose(); } /** * Tests {@link goog.ui.Control#setAriaLabel}. */ function testSetAriaLabel_render() { assertNull( 'Controls must not have any aria label by default', control.getAriaLabel()); control.setAriaLabel('label'); assertEquals('Control must have aria label', 'label', control.getAriaLabel()); control.render(sandbox); var elem = control.getElementStrict(); assertEquals( 'Element must have control\'s aria label after rendering', 'label', goog.a11y.aria.getLabel(elem)); control.setAriaLabel('new label'); assertEquals( 'Element must have the new aria label', 'new label', goog.a11y.aria.getLabel(elem)); } /** * Tests {@link goog.ui.Control#setAriaLabel}. */ function testSetAriaLabel_decorate() { assertNull( 'Controls must not have any aria label by default', control.getAriaLabel()); control.setAriaLabel('label'); assertEquals('Control must have aria label', 'label', control.getAriaLabel()); sandbox.innerHTML = '
' + 'Hello, world!
'; control.decorate(goog.dom.getElement('nodelist')); var elem = control.getElementStrict(); assertEquals( 'Element must have control\'s aria label after rendering', 'label', goog.a11y.aria.getLabel(elem)); assertEquals( 'Element must have the correct role', 'button', elem.getAttribute('role')); control.setAriaLabel('new label'); assertEquals( 'Element must have the new aria label', 'new label', goog.a11y.aria.getLabel(elem)); } /** * Tests {@link goog.ui.Control#setContent}. */ function testSetContent() { control.setContent('Bye'); assertEquals( 'Unrendered control control must have expected contents', 'Bye', control.getContent()); assertNull('No DOM must be created by setContent', control.getElement()); control.createDom(); assertEquals( 'Rendered control\'s DOM must have expected contents', 'Bye', control.getElement().innerHTML); control.setContent(null); assertNull( 'Rendered control must have expected contents', control.getContent()); assertEquals( 'Rendered control\'s DOM must have expected contents', '', control.getElement().innerHTML); control.setContent([ goog.dom.createDom( goog.dom.TagName.DIV, null, goog.dom.createDom(goog.dom.TagName.SPAN, null, 'Hello')), 'World' ]); assertHTMLEquals( 'Control\'s DOM must be updated', '
Hello
World', control.getElement().innerHTML); } /** * Tests {@link goog.ui.Control#setContentInternal}. */ function testSetContentInternal() { control.render(sandbox); assertEquals( 'Control must have expected content after rendering', 'Hello', control.getContent()); control.setContentInternal('Bye'); assertEquals( 'Control must have expected contents', 'Bye', control.getContent()); assertEquals( 'Control\'s DOM must be unchanged', 'Hello', control.getElement().innerHTML); } /** * Tests {@link goog.ui.Control#getCaption}. */ function testGetCaption() { assertEquals( 'Empty control\'s caption must be empty string', '', (new goog.ui.Control(null)).getCaption()); assertEquals( 'Caption must have expected value', 'Hello', control.getCaption()); sandbox.innerHTML = '
Hello, world!
'; control.decorate(goog.dom.getElement('nodelist')); assertEquals( 'Caption must have expected value', 'Hello, world!', control.getCaption()); var arrayContent = goog.array.clone( goog.dom.safeHtmlToNode( goog.html.testing.newSafeHtmlForTest( ' foo bar ')).childNodes); control.setContent(arrayContent); assertEquals( 'whitespaces must be normalized in the caption', 'foo bar', control.getCaption()); control.setContent('\xa0foo'); assertEquals( 'indenting spaces must be kept', '\xa0foo', control.getCaption()); } /** * Tests {@link goog.ui.Control#setCaption}. */ function testSetCaption() { control.setCaption('Hello, world!'); assertEquals( 'Control must have a string caption "Hello, world!"', 'Hello, world!', control.getCaption()); } /** * Tests {@link goog.ui.Control#setRightToLeft}. */ function testSetRightToLeft() { control.createDom(); assertFalse( 'Control\'s element must not have right-to-left class', goog.dom.classlist.contains(control.getElement(), 'goog-control-rtl')); control.setRightToLeft(true); assertTrue( 'Control\'s element must have right-to-left class', goog.dom.classlist.contains(control.getElement(), 'goog-control-rtl')); control.render(sandbox); assertThrows( 'Changing the render direction of a control already in ' + 'the document is an error', function() { control.setRightToLeft(false); }); } /** * Tests {@link goog.ui.Control#isAllowTextSelection}. */ function testIsAllowTextSelection() { assertFalse( 'Controls must not allow text selection by default', control.isAllowTextSelection()); } /** * Tests {@link goog.ui.Control#setAllowTextSelection}. */ function testSetAllowTextSelection() { assertFalse( 'Controls must not allow text selection by default', control.isAllowTextSelection()); control.setAllowTextSelection(true); assertTrue( 'Control must allow text selection', control.isAllowTextSelection()); control.setAllowTextSelection(false); assertFalse( 'Control must no longer allow text selection', control.isAllowTextSelection()); control.render(sandbox); assertFalse( 'Control must not allow text selection even after rendered', control.isAllowTextSelection()); control.setAllowTextSelection(true); assertTrue( 'Control must once again allow text selection', control.isAllowTextSelection()); } /** * Tests {@link goog.ui.Control#isVisible}. */ function testIsVisible() { assertTrue('Controls must be visible by default', control.isVisible()); } /** * Tests {@link goog.ui.Control#setVisible} before it is rendered. */ function testSetVisible() { assertFalse( 'setVisible(true) must return false if already visible', control.setVisible(true)); assertTrue('No events must have been dispatched', noEventsDispatched()); assertTrue( 'setVisible(false) must return true if previously visible', control.setVisible(false)); assertEquals( 'One HIDE event must have been dispatched', 1, getEventCount(control, goog.ui.Component.EventType.HIDE)); assertFalse('Control must no longer be visible', control.isVisible()); assertTrue( 'setVisible(true) must return true if previously hidden', control.setVisible(true)); assertEquals( 'One SHOW event must have been dispatched', 1, getEventCount(control, goog.ui.Component.EventType.SHOW)); assertTrue('Control must be visible', control.isVisible()); } /** * Tests {@link goog.ui.Control#setVisible} after it is rendered. */ function testSetVisibleForRenderedControl() { control.render(sandbox); assertTrue( 'No events must have been dispatched during rendering', noEventsDispatched()); assertFalse( 'setVisible(true) must return false if already visible', control.setVisible(true)); assertTrue('No events must have been dispatched', noEventsDispatched()); assertTrue( 'Control\'s element must be visible', control.getElement().style.display != 'none'); assertTrue( 'setVisible(false) must return true if previously visible', control.setVisible(false)); assertEquals( 'One HIDE event must have been dispatched', 1, getEventCount(control, goog.ui.Component.EventType.HIDE)); assertFalse('Control must no longer be visible', control.isVisible()); assertTrue( 'Control\'s element must be hidden', control.getElement().style.display == 'none'); assertTrue( 'setVisible(true) must return true if previously hidden', control.setVisible(true)); assertEquals( 'One SHOW event must have been dispatched', 1, getEventCount(control, goog.ui.Component.EventType.SHOW)); assertTrue('Control must be visible', control.isVisible()); assertTrue( 'Control\'s element must be visible', control.getElement().style.display != 'none'); } /** * Tests {@link goog.ui.Control#setVisible} for disabled non-focusable * controls. */ function testSetVisibleForDisabledNonFocusableControl() { // Hidden, disabled, non-focusable control becoming visible. control.setEnabled(false); control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.render(sandbox); assertTrue('Control must be visible', control.isVisible()); assertFalse( 'Control must not have a tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); // Visible, disabled, non-focusable control becoming hidden. control.getKeyEventTarget().focus(); assertEquals( 'Control must not have dispatched FOCUS', 0, getEventCount(control, goog.ui.Component.EventType.FOCUS)); assertFalse('Control must not have keyboard focus', control.isFocused()); control.setVisible(false); assertFalse('Control must be hidden', control.isVisible()); assertFalse( 'Control must not have a tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); assertEquals( 'Control must have dispatched HIDE', 1, getEventCount(control, goog.ui.Component.EventType.HIDE)); assertEquals( 'Control must not have dispatched BLUR', 0, getEventCount(control, goog.ui.Component.EventType.BLUR)); } /** * Tests {@link goog.ui.Control#setVisible} for disabled focusable controls. */ function testSetVisibleForDisabledFocusableControl() { // Hidden, disabled, focusable control becoming visible. control.setEnabled(false); control.setSupportedState(goog.ui.Component.State.FOCUSED, true); control.render(sandbox); assertTrue('Control must be visible', control.isVisible()); assertFalse( 'Control must not have a tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); // Visible, disabled, focusable control becoming hidden. control.getKeyEventTarget().focus(); assertEquals( 'Control must not have dispatched FOCUS', 0, getEventCount(control, goog.ui.Component.EventType.FOCUS)); assertFalse('Control must not have keyboard focus', control.isFocused()); control.setVisible(false); assertFalse('Control must be hidden', control.isVisible()); assertFalse( 'Control must not have a tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); assertEquals( 'Control must have dispatched HIDE', 1, getEventCount(control, goog.ui.Component.EventType.HIDE)); assertEquals( 'Control must not have dispatched BLUR', 0, getEventCount(control, goog.ui.Component.EventType.BLUR)); } /** * Tests {@link goog.ui.Control#setVisible} for enabled non-focusable * controls. */ function testSetVisibleForEnabledNonFocusableControl() { // Hidden, enabled, non-focusable control becoming visible. control.setEnabled(true); control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.render(sandbox); assertTrue('Control must be visible', control.isVisible()); assertFalse( 'Control must not have a tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); if (testFocus) { // Visible, enabled, non-focusable control becoming hidden. control.getKeyEventTarget().focus(); assertEquals( 'Control must not have dispatched FOCUS', 0, getEventCount(control, goog.ui.Component.EventType.FOCUS)); assertFalse('Control must not have keyboard focus', control.isFocused()); control.setVisible(false); assertFalse('Control must be hidden', control.isVisible()); assertFalse( 'Control must not have a tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); assertEquals( 'Control must have dispatched HIDE', 1, getEventCount(control, goog.ui.Component.EventType.HIDE)); assertEquals( 'Control must not have dispatched BLUR', 0, getEventCount(control, goog.ui.Component.EventType.BLUR)); } } /** * Tests {@link goog.ui.Control#setVisible} for enabled focusable controls. */ function testSetVisibleForEnabledFocusableControl() { // Hidden, enabled, focusable control becoming visible. control.setEnabled(true); control.setSupportedState(goog.ui.Component.State.FOCUSED, true); control.render(sandbox); assertTrue('Control must be visible', control.isVisible()); if (testFocus) { // Expected to fail on Mac Safari prior to version 527. expectedFailures.expectFailureFor(isMacSafari3()); try { // Mac Safari currently doesn't support tabIndex on arbitrary // elements. assertTrue( 'Control must have a tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); } catch (e) { expectedFailures.handleException(e); } // Visible, enabled, focusable control becoming hidden. control.getKeyEventTarget().focus(); // Expected to fail on IE. expectedFailures.expectFailureFor(goog.userAgent.IE); try { // IE dispatches focus and blur events asynchronously! assertEquals( 'Control must have dispatched FOCUS', 1, getEventCount(control, goog.ui.Component.EventType.FOCUS)); assertTrue('Control must have keyboard focus', control.isFocused()); } catch (e) { expectedFailures.handleException(e); } control.setVisible(false); assertFalse('Control must be hidden', control.isVisible()); assertFalse( 'Control must not have a tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); assertEquals( 'Control must have dispatched HIDE', 1, getEventCount(control, goog.ui.Component.EventType.HIDE)); // Expected to fail on IE. expectedFailures.expectFailureFor(goog.userAgent.IE); try { // IE dispatches focus and blur events asynchronously! assertEquals( 'Control must have dispatched BLUR', 1, getEventCount(control, goog.ui.Component.EventType.BLUR)); assertFalse( 'Control must no longer have keyboard focus', control.isFocused()); } catch (e) { expectedFailures.handleException(e); } } } /** * Tests {@link goog.ui.Control#isEnabled}. */ function testIsEnabled() { assertTrue('Controls must be enabled by default', control.isEnabled()); } /** * Tests {@link goog.ui.Control#setEnabled}. */ function testSetEnabled() { control.render(sandbox); control.setHighlighted(true); control.setActive(true); control.getKeyEventTarget().focus(); resetEventCount(); control.setEnabled(true); assertTrue('No events must have been dispatched', noEventsDispatched()); assertTrue('Control must be enabled', control.isEnabled()); assertTrue('Control must be highlighted', control.isHighlighted()); assertTrue('Control must be active', control.isActive()); var elem = control.getElementStrict(); assertTrue( 'Control element must not have aria-disabled', goog.string.isEmptyOrWhitespace(aria.getState(elem, State.DISABLED))); assertEquals( 'Control element must have a tabIndex of 0', 0, goog.string.toNumber(elem.getAttribute('tabIndex') || '')); if (testFocus) { // Expected to fail on IE and Mac Safari 3. IE calls focus handlers // asynchronously, and Mac Safari 3 doesn't support keyboard focus. expectedFailures.expectFailureFor(goog.userAgent.IE); expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue('Control must be focused', control.isFocused()); } catch (e) { expectedFailures.handleException(e); } } resetEventCount(); control.setEnabled(false); assertEquals( 'One DISABLE event must have been dispatched', 1, getEventCount(control, goog.ui.Component.EventType.DISABLE)); assertFalse('Control must be disabled', control.isEnabled()); assertFalse('Control must not be highlighted', control.isHighlighted()); assertFalse('Control must not be active', control.isActive()); assertFalse('Control must not be focused', control.isFocused()); assertEquals( 'Control element must have aria-disabled true', 'true', aria.getState(control.getElementStrict(), State.DISABLED)); assertNull( 'Control element must not have a tabIndex', control.getElement().getAttribute('tabIndex')); control.setEnabled(true); control.exitDocument(); var cssClass = goog.getCssName(goog.ui.ControlRenderer.CSS_CLASS, 'disabled'); var element = goog.dom.createDom(goog.dom.TagName.DIV, {tabIndex: 0}); element.className = cssClass; goog.dom.appendChild(sandbox, element); control.decorate(element); assertEquals( 'Control element must have aria-disabled true', 'true', aria.getState(control.getElementStrict(), State.DISABLED)); assertNull( 'Control element must not have a tabIndex', control.getElement().getAttribute('tabIndex')); control.setEnabled(true); elem = control.getElementStrict(); assertEquals( 'Control element must have aria-disabled false', 'false', aria.getState(elem, State.DISABLED)); assertEquals( 'Control element must have tabIndex 0', 0, goog.string.toNumber(elem.getAttribute('tabIndex') || '')); } /** * Tests {@link goog.ui.Control#setState} when using * goog.ui.Component.State.DISABLED. */ function testSetStateWithDisabled() { control.render(sandbox); control.setHighlighted(true); control.setActive(true); control.getKeyEventTarget().focus(); resetEventCount(); control.setState(goog.ui.Component.State.DISABLED, false); assertTrue('No events must have been dispatched', noEventsDispatched()); assertTrue('Control must be enabled', control.isEnabled()); assertTrue('Control must be highlighted', control.isHighlighted()); assertTrue('Control must be active', control.isActive()); assertTrue( 'Control element must not have aria-disabled', goog.string.isEmptyOrWhitespace( aria.getState(control.getElementStrict(), State.DISABLED))); assertEquals( 'Control element must have a tabIndex of 0', 0, goog.string.toNumber( control.getElement().getAttribute('tabIndex') || '')); if (testFocus) { // Expected to fail on IE and Mac Safari 3. IE calls focus handlers // asynchronously, and Mac Safari 3 doesn't support keyboard focus. expectedFailures.expectFailureFor(goog.userAgent.IE); expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue('Control must be focused', control.isFocused()); } catch (e) { expectedFailures.handleException(e); } } resetEventCount(); control.setState(goog.ui.Component.State.DISABLED, true); assertEquals( 'One DISABLE event must have been dispatched', 1, getEventCount(control, goog.ui.Component.EventType.DISABLE)); assertFalse('Control must be disabled', control.isEnabled()); assertFalse('Control must not be highlighted', control.isHighlighted()); assertFalse('Control must not be active', control.isActive()); assertFalse('Control must not be focused', control.isFocused()); assertEquals( 'Control element must have aria-disabled true', 'true', aria.getState(control.getElementStrict(), State.DISABLED)); assertNull( 'Control element must not have a tabIndex', control.getElement().getAttribute('tabIndex')); control.setState(goog.ui.Component.State.DISABLED, false); control.exitDocument(); var cssClass = goog.getCssName(goog.ui.ControlRenderer.CSS_CLASS, 'disabled'); var element = goog.dom.createDom(goog.dom.TagName.DIV, {tabIndex: 0}); element.className = cssClass; goog.dom.appendChild(sandbox, element); control.decorate(element); assertEquals( 'Control element must have aria-disabled true', 'true', aria.getState(control.getElementStrict(), State.DISABLED)); assertNull( 'Control element must not have a tabIndex', control.getElement().getAttribute('tabIndex')); control.setState(goog.ui.Component.State.DISABLED, false); elem = control.getElementStrict(); assertEquals( 'Control element must have aria-disabled false', 'false', aria.getState(elem, State.DISABLED)); assertEquals( 'Control element must have tabIndex 0', 0, goog.string.toNumber(elem.getAttribute('tabIndex') || '')); } /** * Tests {@link goog.ui.Control#setEnabled} when the control has a parent. */ function testSetEnabledWithParent() { var child = new goog.ui.Control(null); child.setDispatchTransitionEvents(goog.ui.Component.State.ALL, true); control.addChild(child, true /* opt_render */); control.setEnabled(false); resetEventCount(); assertFalse('Parent must be disabled', control.isEnabled()); assertTrue('Child must be enabled', child.isEnabled()); child.setEnabled(false); assertTrue( 'No events must have been dispatched when child is disabled', noEventsDispatched()); assertTrue('Child must still be enabled', child.isEnabled()); resetEventCount(); control.setEnabled(true); assertEquals( 'One ENABLE event must have been dispatched by the parent', 1, getEventCount(control, goog.ui.Component.EventType.ENABLE)); assertTrue('Parent must be enabled', control.isEnabled()); assertTrue('Child must still be enabled', child.isEnabled()); resetEventCount(); child.setEnabled(false); assertEquals( 'One DISABLE event must have been dispatched by the child', 1, getEventCount(child, goog.ui.Component.EventType.DISABLE)); assertTrue('Parent must still be enabled', control.isEnabled()); assertFalse('Child must now be disabled', child.isEnabled()); resetEventCount(); control.setEnabled(false); assertEquals( 'One DISABLE event must have been dispatched by the parent', 1, getEventCount(control, goog.ui.Component.EventType.DISABLE)); assertFalse('Parent must now be disabled', control.isEnabled()); assertFalse('Child must still be disabled', child.isEnabled()); child.dispose(); } /** * Tests {@link goog.ui.Control#isHighlighted}. */ function testIsHighlighted() { assertFalse( 'Controls must not be highlighted by default', control.isHighlighted()); } /** * Tests {@link goog.ui.Control#setHighlighted}. */ function testSetHighlighted() { control.setSupportedState(goog.ui.Component.State.HOVER, false); control.setHighlighted(true); assertFalse( 'Control must not be highlighted, because it isn\'t ' + 'highlightable', control.isHighlighted()); assertTrue( 'Control must not have dispatched any events', noEventsDispatched()); control.setSupportedState(goog.ui.Component.State.HOVER, true); control.setHighlighted(true); assertTrue('Control must be highlighted', control.isHighlighted()); assertEquals( 'Control must have dispatched a HIGHLIGHT event', 1, getEventCount(control, goog.ui.Component.EventType.HIGHLIGHT)); control.setHighlighted(true); assertTrue('Control must still be highlighted', control.isHighlighted()); assertEquals( 'Control must not dispatch more HIGHLIGHT events', 1, getEventCount(control, goog.ui.Component.EventType.HIGHLIGHT)); control.setHighlighted(false); assertFalse('Control must not be highlighted', control.isHighlighted()); assertEquals( 'Control must have dispatched an UNHIGHLIGHT event', 1, getEventCount(control, goog.ui.Component.EventType.UNHIGHLIGHT)); control.setEnabled(false); assertFalse('Control must be disabled', control.isEnabled()); control.setHighlighted(true); assertTrue( 'Control must be highlighted, even when disabled', control.isHighlighted()); assertEquals( 'Control must have dispatched another HIGHLIGHT event', 2, getEventCount(control, goog.ui.Component.EventType.HIGHLIGHT)); } /** * Tests {@link goog.ui.Control#isActive}. */ function testIsActive() { assertFalse('Controls must not be active by default', control.isActive()); } /** * Tests {@link goog.ui.Control#setActive}. */ function testSetActive() { control.setSupportedState(goog.ui.Component.State.ACTIVE, false); control.setActive(true); assertFalse( 'Control must not be active, because it isn\'t activateable', control.isActive()); assertTrue( 'Control must not have dispatched any events', noEventsDispatched()); control.setSupportedState(goog.ui.Component.State.ACTIVE, true); control.setActive(true); assertTrue('Control must be active', control.isActive()); assertEquals( 'Control must have dispatched an ACTIVATE event', 1, getEventCount(control, goog.ui.Component.EventType.ACTIVATE)); control.setActive(true); assertTrue('Control must still be active', control.isActive()); assertEquals( 'Control must not dispatch more ACTIVATE events', 1, getEventCount(control, goog.ui.Component.EventType.ACTIVATE)); control.setEnabled(false); assertFalse('Control must be disabled', control.isEnabled()); assertFalse('Control must not be active', control.isActive()); assertEquals( 'Control must have dispatched a DEACTIVATE event', 1, getEventCount(control, goog.ui.Component.EventType.DEACTIVATE)); } /** * Tests disposing the control from an action event handler. */ function testDisposeOnAction() { goog.events.listen(control, goog.ui.Component.EventType.ACTION, function(e) { control.dispose(); }); // Control must not throw an exception if disposed of in an ACTION event // handler. control.performActionInternal(); control.setActive(true); assertTrue('Control should have been disposed of', control.isDisposed()); } /** * Tests {@link goog.ui.Control#isSelected}. */ function testIsSelected() { assertFalse('Controls must not be selected by default', control.isSelected()); } /** * Tests {@link goog.ui.Control#setSelected}. */ function testSetSelected() { control.setSupportedState(goog.ui.Component.State.SELECTED, false); control.setSelected(true); assertFalse( 'Control must not be selected, because it isn\'t selectable', control.isSelected()); assertTrue( 'Control must not have dispatched any events', noEventsDispatched()); control.setSupportedState(goog.ui.Component.State.SELECTED, true); control.setSelected(true); assertTrue('Control must be selected', control.isSelected()); assertEquals( 'Control must have dispatched a SELECT event', 1, getEventCount(control, goog.ui.Component.EventType.SELECT)); control.setSelected(true); assertTrue('Control must still be selected', control.isSelected()); assertEquals( 'Control must not dispatch more SELECT events', 1, getEventCount(control, goog.ui.Component.EventType.SELECT)); control.setSelected(false); assertFalse('Control must not be selected', control.isSelected()); assertEquals( 'Control must have dispatched an UNSELECT event', 1, getEventCount(control, goog.ui.Component.EventType.UNSELECT)); control.setEnabled(false); assertFalse('Control must be disabled', control.isEnabled()); control.setSelected(true); assertTrue( 'Control must be selected, even when disabled', control.isSelected()); assertEquals( 'Control must have dispatched another SELECT event', 2, getEventCount(control, goog.ui.Component.EventType.SELECT)); } /** * Tests {@link goog.ui.Control#isChecked}. */ function testIsChecked() { assertFalse('Controls must not be checked by default', control.isChecked()); } /** * Tests {@link goog.ui.Control#setChecked}. */ function testSetChecked() { control.setSupportedState(goog.ui.Component.State.CHECKED, false); control.setChecked(true); assertFalse( 'Control must not be checked, because it isn\'t checkable', control.isChecked()); assertTrue( 'Control must not have dispatched any events', noEventsDispatched()); control.setSupportedState(goog.ui.Component.State.CHECKED, true); control.setChecked(true); assertTrue('Control must be checked', control.isChecked()); assertEquals( 'Control must have dispatched a CHECK event', 1, getEventCount(control, goog.ui.Component.EventType.CHECK)); control.setChecked(true); assertTrue('Control must still be checked', control.isChecked()); assertEquals( 'Control must not dispatch more CHECK events', 1, getEventCount(control, goog.ui.Component.EventType.CHECK)); control.setChecked(false); assertFalse('Control must not be checked', control.isChecked()); assertEquals( 'Control must have dispatched an UNCHECK event', 1, getEventCount(control, goog.ui.Component.EventType.UNCHECK)); control.setEnabled(false); assertFalse('Control must be disabled', control.isEnabled()); control.setChecked(true); assertTrue( 'Control must be checked, even when disabled', control.isChecked()); assertEquals( 'Control must have dispatched another CHECK event', 2, getEventCount(control, goog.ui.Component.EventType.CHECK)); } /** * Tests {@link goog.ui.Control#isFocused}. */ function testIsFocused() { assertFalse('Controls must not be focused by default', control.isFocused()); } /** * Tests {@link goog.ui.Control#setFocused}. */ function testSetFocused() { control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.setFocused(true); assertFalse( 'Control must not be focused, because it isn\'t focusable', control.isFocused()); assertTrue( 'Control must not have dispatched any events', noEventsDispatched()); control.setSupportedState(goog.ui.Component.State.FOCUSED, true); control.setFocused(true); assertTrue('Control must be focused', control.isFocused()); assertEquals( 'Control must have dispatched a FOCUS event', 1, getEventCount(control, goog.ui.Component.EventType.FOCUS)); control.setFocused(true); assertTrue('Control must still be focused', control.isFocused()); assertEquals( 'Control must not dispatch more FOCUS events', 1, getEventCount(control, goog.ui.Component.EventType.FOCUS)); control.setFocused(false); assertFalse('Control must not be focused', control.isFocused()); assertEquals( 'Control must have dispatched an BLUR event', 1, getEventCount(control, goog.ui.Component.EventType.BLUR)); control.setEnabled(false); assertFalse('Control must be disabled', control.isEnabled()); control.setFocused(true); assertTrue( 'Control must be focused, even when disabled', control.isFocused()); assertEquals( 'Control must have dispatched another FOCUS event', 2, getEventCount(control, goog.ui.Component.EventType.FOCUS)); } /** * Tests {@link goog.ui.Control#isOpen}. */ function testIsOpen() { assertFalse('Controls must not be open by default', control.isOpen()); } /** * Tests {@link goog.ui.Control#setOpen}. */ function testSetOpen() { control.setSupportedState(goog.ui.Component.State.OPENED, false); control.setOpen(true); assertFalse( 'Control must not be opened, because it isn\'t openable', control.isOpen()); assertTrue( 'Control must not have dispatched any events', noEventsDispatched()); control.setSupportedState(goog.ui.Component.State.OPENED, true); control.setOpen(true); assertTrue('Control must be opened', control.isOpen()); assertEquals( 'Control must have dispatched a OPEN event', 1, getEventCount(control, goog.ui.Component.EventType.OPEN)); control.setOpen(true); assertTrue('Control must still be opened', control.isOpen()); assertEquals( 'Control must not dispatch more OPEN events', 1, getEventCount(control, goog.ui.Component.EventType.OPEN)); control.setOpen(false); assertFalse('Control must not be opened', control.isOpen()); assertEquals( 'Control must have dispatched an CLOSE event', 1, getEventCount(control, goog.ui.Component.EventType.CLOSE)); control.setEnabled(false); assertFalse('Control must be disabled', control.isEnabled()); control.setOpen(true); assertTrue('Control must be opened, even when disabled', control.isOpen()); assertEquals( 'Control must have dispatched another OPEN event', 2, getEventCount(control, goog.ui.Component.EventType.OPEN)); } /** * Tests {@link goog.ui.Control#getState}. */ function testGetState() { assertEquals( 'Controls must be in the default state', 0x00, control.getState()); } /** * Tests {@link goog.ui.Control#hasState}. */ function testHasState() { assertFalse( 'Control must not be disabled', control.hasState(goog.ui.Component.State.DISABLED)); assertFalse( 'Control must not be in the HOVER state', control.hasState(goog.ui.Component.State.HOVER)); assertFalse( 'Control must not be active', control.hasState(goog.ui.Component.State.ACTIVE)); assertFalse( 'Control must not be selected', control.hasState(goog.ui.Component.State.SELECTED)); assertFalse( 'Control must not be checked', control.hasState(goog.ui.Component.State.CHECKED)); assertFalse( 'Control must not be focused', control.hasState(goog.ui.Component.State.FOCUSED)); assertFalse( 'Control must not be open', control.hasState(goog.ui.Component.State.OPEN)); } /** * Tests {@link goog.ui.Control#setState}. */ function testSetState() { control.createDom(); control.setSupportedState(goog.ui.Component.State.ACTIVE, false); assertFalse( 'Control must not be active', control.hasState(goog.ui.Component.State.ACTIVE)); control.setState(goog.ui.Component.State.ACTIVE, true); assertFalse( 'Control must still be inactive (because it doesn\'t ' + 'support the ACTIVE state)', control.hasState(goog.ui.Component.State.ACTIVE)); control.setSupportedState(goog.ui.Component.State.ACTIVE, true); control.setState(goog.ui.Component.State.ACTIVE, true); assertTrue( 'Control must be active', control.hasState(goog.ui.Component.State.ACTIVE)); assertTrue( 'Control must have the active CSS style', goog.dom.classlist.contains(control.getElement(), 'goog-control-active')); control.setState(goog.ui.Component.State.ACTIVE, true); assertTrue( 'Control must still be active', control.hasState(goog.ui.Component.State.ACTIVE)); assertTrue( 'Control must still have the active CSS style', goog.dom.classlist.contains(control.getElement(), 'goog-control-active')); assertTrue('No events must have been dispatched', noEventsDispatched()); } /** * Tests {@link goog.ui.Control#setStateInternal}. */ function testSetStateInternal() { control.setStateInternal(0x00); assertEquals('State should be 0x00', 0x00, control.getState()); control.setStateInternal(0x17); assertEquals('State should be 0x17', 0x17, control.getState()); } /** * Tests {@link goog.ui.Control#isSupportedState}. */ function testIsSupportedState() { assertTrue( 'Control must support DISABLED', control.isSupportedState(goog.ui.Component.State.DISABLED)); assertTrue( 'Control must support HOVER', control.isSupportedState(goog.ui.Component.State.HOVER)); assertTrue( 'Control must support ACTIVE', control.isSupportedState(goog.ui.Component.State.ACTIVE)); assertTrue( 'Control must support FOCUSED', control.isSupportedState(goog.ui.Component.State.FOCUSED)); assertFalse( 'Control must no support SELECTED', control.isSupportedState(goog.ui.Component.State.SELECTED)); assertFalse( 'Control must no support CHECKED', control.isSupportedState(goog.ui.Component.State.CHECKED)); assertFalse( 'Control must no support OPENED', control.isSupportedState(goog.ui.Component.State.OPENED)); } /** * Tests {@link goog.ui.Control#setSupportedState}. */ function testSetSupportedState() { control.setSupportedState(goog.ui.Component.State.HOVER, true); assertTrue( 'Control must still support HOVER', control.isSupportedState(goog.ui.Component.State.HOVER)); control.setSupportedState(goog.ui.Component.State.HOVER, false); assertFalse( 'Control must no longer support HOVER', control.isSupportedState(goog.ui.Component.State.HOVER)); control.setState(goog.ui.Component.State.ACTIVE, true); control.setSupportedState(goog.ui.Component.State.ACTIVE, false); assertFalse( 'Control must no longer support ACTIVE', control.isSupportedState(goog.ui.Component.State.ACTIVE)); assertFalse( 'Control must no longer be in the ACTIVE state', control.hasState(goog.ui.Component.State.ACTIVE)); control.render(sandbox); control.setSupportedState(goog.ui.Component.State.FOCUSED, true); control.setState(goog.ui.Component.State.FOCUSED, true); assertThrows( 'Must not be able to disable support for the FOCUSED ' + "state for a control that's already in the document and focused", function() { control.setSupportedState(goog.ui.Component.State.FOCUSED, false); }); assertTrue('No events must have been dispatched', noEventsDispatched()); } /** * Tests {@link goog.ui.Control#isAutoState}. */ function testIsAutoState() { assertTrue( 'Control must have DISABLED as an auto-state', control.isAutoState(goog.ui.Component.State.DISABLED)); assertTrue( 'Control must have HOVER as an auto-state', control.isAutoState(goog.ui.Component.State.HOVER)); assertTrue( 'Control must have ACTIVE as an auto-state', control.isAutoState(goog.ui.Component.State.ACTIVE)); assertTrue( 'Control must have FOCUSED as an auto-state', control.isAutoState(goog.ui.Component.State.FOCUSED)); assertFalse( 'Control must not have SELECTED as an auto-state', control.isAutoState(goog.ui.Component.State.SELECTED)); assertFalse( 'Control must not have CHECKED as an auto-state', control.isAutoState(goog.ui.Component.State.CHECKED)); assertFalse( 'Control must not have OPENED as an auto-state', control.isAutoState(goog.ui.Component.State.OPENED)); assertTrue('No events must have been dispatched', noEventsDispatched()); } /** * Tests {@link goog.ui.Control#setAutoStates}. */ function testSetAutoStates() { control.setAutoStates(goog.ui.Component.State.HOVER, false); assertFalse( 'Control must not have HOVER as an auto-state', control.isAutoState(goog.ui.Component.State.HOVER)); control.setAutoStates( goog.ui.Component.State.ACTIVE | goog.ui.Component.State.FOCUSED, false); assertFalse( 'Control must not have ACTIVE as an auto-state', control.isAutoState(goog.ui.Component.State.ACTIVE)); assertFalse( 'Control must not have FOCUSED as an auto-state', control.isAutoState(goog.ui.Component.State.FOCUSED)); control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.setAutoStates(goog.ui.Component.State.FOCUSED, true); assertFalse( 'Control must not have FOCUSED as an auto-state if it no ' + 'longer supports FOCUSED', control.isAutoState(goog.ui.Component.State.FOCUSED)); assertTrue('No events must have been dispatched', noEventsDispatched()); } /** * Tests {@link goog.ui.Control#isDispatchTransitionEvents}. */ function testIsDispatchTransitionEvents() { assertTrue( 'Control must dispatch DISABLED transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.DISABLED)); assertTrue( 'Control must dispatch HOVER transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.HOVER)); assertTrue( 'Control must dispatch ACTIVE transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.ACTIVE)); assertTrue( 'Control must dispatch FOCUSED transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.FOCUSED)); assertFalse( 'Control must not dispatch SELECTED transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.SELECTED)); assertFalse( 'Control must not dispatch CHECKED transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.CHECKED)); assertFalse( 'Control must not dispatch OPENED transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.OPENED)); assertTrue('No events must have been dispatched', noEventsDispatched()); } /** * Tests {@link goog.ui.Control#setDispatchTransitionEvents}. */ function testSetDispatchTransitionEvents() { control.setDispatchTransitionEvents(goog.ui.Component.State.HOVER, false); assertFalse( 'Control must not dispatch HOVER transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.HOVER)); control.setSupportedState(goog.ui.Component.State.SELECTED, true); control.setDispatchTransitionEvents(goog.ui.Component.State.SELECTED, true); assertTrue( 'Control must dispatch SELECTED transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.SELECTED)); assertTrue('No events must have been dispatched', noEventsDispatched()); } /** * Tests {@link goog.ui.Control#isTransitionAllowed}. */ function testIsTransitionAllowed() { assertTrue( 'Control must support the HOVER state', control.isSupportedState(goog.ui.Component.State.HOVER)); assertFalse( 'Control must not be in the HOVER state', control.hasState(goog.ui.Component.State.HOVER)); assertTrue( 'Control must dispatch HOVER transition events', control.isDispatchTransitionEvents(goog.ui.Component.State.HOVER)); assertTrue( 'Control must be allowed to transition to the HOVER state', control.isTransitionAllowed(goog.ui.Component.State.HOVER, true)); assertEquals( 'Control must have dispatched one HIGHLIGHT event', 1, getEventCount(control, goog.ui.Component.EventType.HIGHLIGHT)); assertFalse( 'Control must not be highlighted', control.hasState(goog.ui.Component.State.HOVER)); control.setState(goog.ui.Component.State.HOVER, true); control.setDispatchTransitionEvents(goog.ui.Component.State.HOVER, false); assertTrue( 'Control must be allowed to transition from the HOVER state', control.isTransitionAllowed(goog.ui.Component.State.HOVER, false)); assertEquals( 'Control must not have dispatched any UNHIGHLIGHT events', 0, getEventCount(control, goog.ui.Component.EventType.UNHIGHLIGHT)); assertTrue( 'Control must still be highlighted', control.hasState(goog.ui.Component.State.HOVER)); control.setSupportedState(goog.ui.Component.State.FOCUSED, false); resetEventCount(); assertFalse( 'Control doesn\'t support the FOCUSED state', control.isSupportedState(goog.ui.Component.State.FOCUSED)); assertFalse( 'Control must not be FOCUSED', control.hasState(goog.ui.Component.State.FOCUSED)); assertFalse( 'Control must not be allowed to transition to the FOCUSED ' + 'state', control.isTransitionAllowed(goog.ui.Component.State.FOCUSED, true)); assertEquals( 'Control must not have dispatched any FOCUS events', 0, getEventCount(control, goog.ui.Component.EventType.FOCUS)); control.setEnabled(false); resetEventCount(); assertTrue( 'Control must support the DISABLED state', control.isSupportedState(goog.ui.Component.State.DISABLED)); assertTrue( 'Control must be DISABLED', control.hasState(goog.ui.Component.State.DISABLED)); assertFalse( 'Control must not be allowed to transition to the DISABLED ' + 'state, because it is already there', control.isTransitionAllowed(goog.ui.Component.State.DISABLED, true)); assertEquals( 'Control must not have dispatched any ENABLE events', 0, getEventCount(control, goog.ui.Component.EventType.ENABLE)); } /** * Tests {@link goog.ui.Control#handleKeyEvent}. */ function testHandleKeyEvent() { control.render(); control.isVisible = control.isEnabled = function() { return true; }; goog.testing.events.fireKeySequence( control.getKeyEventTarget(), goog.events.KeyCodes.A); assertEquals( 'Control must not have dispatched an ACTION event', 0, getEventCount(control, goog.ui.Component.EventType.ACTION)); goog.testing.events.fireKeySequence( control.getKeyEventTarget(), goog.events.KeyCodes.ENTER); assertEquals( 'Control must have dispatched an ACTION event', 1, getEventCount(control, goog.ui.Component.EventType.ACTION)); } /** * Tests {@link goog.ui.Control#performActionInternal}. */ function testPerformActionInternal() { assertFalse('Control must not be checked', control.isChecked()); assertFalse('Control must not be selected', control.isSelected()); assertFalse('Control must not be open', control.isOpen()); control.performActionInternal(); assertFalse('Control must not be checked', control.isChecked()); assertFalse('Control must not be selected', control.isSelected()); assertFalse('Control must not be open', control.isOpen()); assertEquals( 'Control must have dispatched an ACTION event', 1, getEventCount(control, goog.ui.Component.EventType.ACTION)); control.setSupportedState(goog.ui.Component.State.CHECKED, true); control.setSupportedState(goog.ui.Component.State.SELECTED, true); control.setSupportedState(goog.ui.Component.State.OPENED, true); control.performActionInternal(); assertTrue('Control must be checked', control.isChecked()); assertTrue('Control must be selected', control.isSelected()); assertTrue('Control must be open', control.isOpen()); assertEquals( 'Control must have dispatched a CHECK event', 1, getEventCount(control, goog.ui.Component.EventType.CHECK)); assertEquals( 'Control must have dispatched a SELECT event', 1, getEventCount(control, goog.ui.Component.EventType.SELECT)); assertEquals( 'Control must have dispatched a OPEN event', 1, getEventCount(control, goog.ui.Component.EventType.OPEN)); assertEquals( 'Control must have dispatched another ACTION event', 2, getEventCount(control, goog.ui.Component.EventType.ACTION)); control.performActionInternal(); assertFalse('Control must not be checked', control.isChecked()); assertTrue('Control must be selected', control.isSelected()); assertFalse('Control must not be open', control.isOpen()); assertEquals( 'Control must have dispatched an UNCHECK event', 1, getEventCount(control, goog.ui.Component.EventType.UNCHECK)); assertEquals( 'Control must not have dispatched an UNSELECT event', 0, getEventCount(control, goog.ui.Component.EventType.UNSELECT)); assertEquals( 'Control must have dispatched a CLOSE event', 1, getEventCount(control, goog.ui.Component.EventType.CLOSE)); assertEquals( 'Control must have dispatched another ACTION event', 3, getEventCount(control, goog.ui.Component.EventType.ACTION)); } /** * Tests {@link goog.ui.Control#handleMouseOver}. */ function testHandleMouseOver() { control.setContent( goog.dom.createDom(goog.dom.TagName.SPAN, {id: 'caption'}, 'Hello')); control.render(sandbox); var element = control.getElement(); var caption = goog.dom.getElement('caption'); // Verify baseline assumptions. assertTrue( 'Caption must be contained within the control', goog.dom.contains(element, caption)); assertTrue('Control must be enabled', control.isEnabled()); assertTrue( 'HOVER must be an auto-state', control.isAutoState(goog.ui.Component.State.HOVER)); assertFalse( 'Control must not start out highlighted', control.isHighlighted()); // Scenario 1: relatedTarget is contained within the control's DOM. goog.testing.events.fireMouseOverEvent(element, caption); assertTrue( 'No events must have been dispatched for internal mouse move', noEventsDispatched()); assertFalse( 'Control must not be highlighted for internal mouse move', control.isHighlighted()); resetEventCount(); // Scenario 2: preventDefault() is called on the ENTER event. var key = goog.events.listen( control, goog.ui.Component.EventType.ENTER, function(e) { e.preventDefault(); }); goog.testing.events.fireMouseOverEvent(element, sandbox); assertEquals( 'Control must have dispatched 1 ENTER event', 1, getEventCount(control, goog.ui.Component.EventType.ENTER)); assertFalse( 'Control must not be highlighted if ENTER is canceled', control.isHighlighted()); goog.events.unlistenByKey(key); resetEventCount(); // Scenario 3: Control is disabled. control.setEnabled(false); goog.testing.events.fireMouseOverEvent(element, sandbox); assertEquals( 'Control must dispatch ENTER event on mouseover even if ' + 'disabled', 1, getEventCount(control, goog.ui.Component.EventType.ENTER)); assertFalse( 'Control must not be highlighted if it is disabled', control.isHighlighted()); control.setEnabled(true); resetEventCount(); // Scenario 4: HOVER is not an auto-state. control.setAutoStates(goog.ui.Component.State.HOVER, false); goog.testing.events.fireMouseOverEvent(element, sandbox); assertEquals( 'Control must dispatch ENTER event on mouseover even if ' + 'HOVER is not an auto-state', 1, getEventCount(control, goog.ui.Component.EventType.ENTER)); assertFalse( 'Control must not be highlighted if HOVER isn\'t an auto-' + 'state', control.isHighlighted()); control.setAutoStates(goog.ui.Component.State.HOVER, true); resetEventCount(); // Scenario 5: All is well. goog.testing.events.fireMouseOverEvent(element, sandbox); assertEquals( 'Control must dispatch ENTER event on mouseover', 1, getEventCount(control, goog.ui.Component.EventType.ENTER)); assertEquals( 'Control must dispatch HIGHLIGHT event on mouseover', 1, getEventCount(control, goog.ui.Component.EventType.HIGHLIGHT)); assertTrue('Control must be highlighted', control.isHighlighted()); resetEventCount(); // Scenario 6: relatedTarget is null control.setHighlighted(false); goog.testing.events.fireMouseOverEvent(element, null); assertEquals( 'Control must dispatch ENTER event on mouseover', 1, getEventCount(control, goog.ui.Component.EventType.ENTER)); assertEquals( 'Control must dispatch HIGHLIGHT event on mouseover', 1, getEventCount(control, goog.ui.Component.EventType.HIGHLIGHT)); assertTrue('Control must be highlighted', control.isHighlighted()); resetEventCount(); } /** * Tests {@link goog.ui.Control#handleMouseOut}. */ function testHandleMouseOut() { control.setContent( goog.dom.createDom(goog.dom.TagName.SPAN, {id: 'caption'}, 'Hello')); control.setHighlighted(true); control.setActive(true); resetEventCount(); control.render(sandbox); var element = control.getElement(); var caption = goog.dom.getElement('caption'); // Verify baseline assumptions. assertTrue( 'Caption must be contained within the control', goog.dom.contains(element, caption)); assertTrue('Control must be enabled', control.isEnabled()); assertTrue( 'HOVER must be an auto-state', control.isAutoState(goog.ui.Component.State.HOVER)); assertTrue( 'ACTIVE must be an auto-state', control.isAutoState(goog.ui.Component.State.ACTIVE)); assertTrue('Control must start out highlighted', control.isHighlighted()); assertTrue('Control must start out active', control.isActive()); // Scenario 1: relatedTarget is contained within the control's DOM. goog.testing.events.fireMouseOutEvent(element, caption); assertTrue( 'No events must have been dispatched for internal mouse move', noEventsDispatched()); assertTrue( 'Control must not be un-highlighted for internal mouse move', control.isHighlighted()); assertTrue( 'Control must not be deactivated for internal mouse move', control.isActive()); resetEventCount(); // Scenario 2: preventDefault() is called on the LEAVE event. var key = goog.events.listen( control, goog.ui.Component.EventType.LEAVE, function(e) { e.preventDefault(); }); goog.testing.events.fireMouseOutEvent(element, sandbox); assertEquals( 'Control must have dispatched 1 LEAVE event', 1, getEventCount(control, goog.ui.Component.EventType.LEAVE)); assertTrue( 'Control must not be un-highlighted if LEAVE is canceled', control.isHighlighted()); assertTrue( 'Control must not be deactivated if LEAVE is canceled', control.isActive()); goog.events.unlistenByKey(key); resetEventCount(); // Scenario 3: ACTIVE is not an auto-state. control.setAutoStates(goog.ui.Component.State.ACTIVE, false); goog.testing.events.fireMouseOutEvent(element, sandbox); assertEquals( 'Control must dispatch LEAVE event on mouseout even if ' + 'ACTIVE is not an auto-state', 1, getEventCount(control, goog.ui.Component.EventType.LEAVE)); assertTrue( 'Control must not be deactivated if ACTIVE isn\'t an auto-' + 'state', control.isActive()); assertFalse( 'Control must be un-highlighted even if ACTIVE isn\'t an ' + 'auto-state', control.isHighlighted()); control.setAutoStates(goog.ui.Component.State.ACTIVE, true); control.setHighlighted(true); resetEventCount(); // Scenario 4: HOVER is not an auto-state. control.setAutoStates(goog.ui.Component.State.HOVER, false); goog.testing.events.fireMouseOutEvent(element, sandbox); assertEquals( 'Control must dispatch LEAVE event on mouseout even if ' + 'HOVER is not an auto-state', 1, getEventCount(control, goog.ui.Component.EventType.LEAVE)); assertFalse( 'Control must be deactivated even if HOVER isn\'t an auto-' + 'state', control.isActive()); assertTrue( 'Control must not be un-highlighted if HOVER isn\'t an auto-' + 'state', control.isHighlighted()); control.setAutoStates(goog.ui.Component.State.HOVER, true); control.setActive(true); resetEventCount(); // Scenario 5: All is well. goog.testing.events.fireMouseOutEvent(element, sandbox); assertEquals( 'Control must dispatch LEAVE event on mouseout', 1, getEventCount(control, goog.ui.Component.EventType.LEAVE)); assertEquals( 'Control must dispatch DEACTIVATE event on mouseout', 1, getEventCount(control, goog.ui.Component.EventType.DEACTIVATE)); assertEquals( 'Control must dispatch UNHIGHLIGHT event on mouseout', 1, getEventCount(control, goog.ui.Component.EventType.UNHIGHLIGHT)); assertFalse('Control must be deactivated', control.isActive()); assertFalse('Control must be unhighlighted', control.isHighlighted()); resetEventCount(); // Scenario 6: relatedTarget is null control.setActive(true); control.setHighlighted(true); goog.testing.events.fireMouseOutEvent(element, null); assertEquals( 'Control must dispatch LEAVE event on mouseout', 1, getEventCount(control, goog.ui.Component.EventType.LEAVE)); assertEquals( 'Control must dispatch DEACTIVATE event on mouseout', 1, getEventCount(control, goog.ui.Component.EventType.DEACTIVATE)); assertEquals( 'Control must dispatch UNHIGHLIGHT event on mouseout', 1, getEventCount(control, goog.ui.Component.EventType.UNHIGHLIGHT)); assertFalse('Control must be deactivated', control.isActive()); assertFalse('Control must be unhighlighted', control.isHighlighted()); resetEventCount(); } function testIsMouseEventWithinElement() { var child = goog.dom.createElement(goog.dom.TagName.DIV); var parent = goog.dom.createDom(goog.dom.TagName.DIV, null, child); var notChild = goog.dom.createElement(goog.dom.TagName.DIV); var event = new goog.testing.events.Event('mouseout'); event.relatedTarget = child; assertTrue( 'Event is within element', goog.ui.Control.isMouseEventWithinElement_(event, parent)); var event = new goog.testing.events.Event('mouseout'); event.relatedTarget = notChild; assertFalse( 'Event is not within element', goog.ui.Control.isMouseEventWithinElement_(event, parent)); } function testHandleMouseDown() { control.render(sandbox); assertFalse( 'preventDefault() must have been called for control that ' + 'doesn\'t support text selection', fireMouseDownAndFocus(control.getElement())); assertTrue('Control must be highlighted', control.isHighlighted()); assertTrue('Control must be active', control.isActive()); if (testFocus) { // Expected to fail on IE and Mac Safari 3. IE calls focus handlers // asynchronously, and Mac Safari 3 doesn't support keyboard focus. expectedFailures.expectFailureFor(goog.userAgent.IE); expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue('Control must be focused', control.isFocused()); } catch (e) { expectedFailures.handleException(e); } } } function testHandleMouseDownForDisabledControl() { control.setEnabled(false); control.render(sandbox); assertFalse( 'preventDefault() must have been called for control that ' + 'doesn\'t support text selection', fireMouseDownAndFocus(control.getElement())); assertFalse('Control must not be highlighted', control.isHighlighted()); assertFalse('Control must not be active', control.isActive()); if (testFocus) { assertFalse('Control must not be focused', control.isFocused()); } } function testHandleMouseDownForNoHoverAutoState() { control.setAutoStates(goog.ui.Component.State.HOVER, false); control.render(sandbox); assertFalse( 'preventDefault() must have been called for control that ' + 'doesn\'t support text selection', fireMouseDownAndFocus(control.getElement())); assertFalse('Control must not be highlighted', control.isHighlighted()); assertTrue('Control must be active', control.isActive()); if (testFocus) { // Expected to fail on IE and Mac Safari 3. IE calls focus handlers // asynchronously, and Mac Safari 3 doesn't support keyboard focus. expectedFailures.expectFailureFor(goog.userAgent.IE); expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue('Control must be focused', control.isFocused()); } catch (e) { expectedFailures.handleException(e); } } } function testHandleMouseDownForRightMouseButton() { control.render(sandbox); assertTrue( 'preventDefault() must not have been called for right ' + 'mouse button', fireMouseDownAndFocus( control.getElement(), goog.events.BrowserEvent.MouseButton.RIGHT)); assertTrue('Control must be highlighted', control.isHighlighted()); assertFalse('Control must not be active', control.isActive()); if (testFocus) { // Expected to fail on IE and Mac Safari 3. IE calls focus handlers // asynchronously, and Mac Safari 3 doesn't support keyboard focus. expectedFailures.expectFailureFor(goog.userAgent.IE); expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue('Control must be focused', control.isFocused()); } catch (e) { expectedFailures.handleException(e); } } } function testHandleMouseDownForNoActiveAutoState() { control.setAutoStates(goog.ui.Component.State.ACTIVE, false); control.render(sandbox); assertFalse( 'preventDefault() must have been called for control that ' + 'doesn\'t support text selection', fireMouseDownAndFocus(control.getElement())); assertTrue('Control must be highlighted', control.isHighlighted()); assertFalse('Control must not be active', control.isActive()); if (testFocus) { // Expected to fail on IE and Mac Safari 3. IE calls focus handlers // asynchronously, and Mac Safari 3 doesn't support keyboard focus. expectedFailures.expectFailureFor(goog.userAgent.IE); expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue('Control must be focused', control.isFocused()); } catch (e) { expectedFailures.handleException(e); } } } function testHandleMouseDownForNonFocusableControl() { control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.render(sandbox); assertFalse( 'preventDefault() must have been called for control that ' + 'doesn\'t support text selection', fireMouseDownAndFocus(control.getElement())); assertTrue('Control must be highlighted', control.isHighlighted()); assertTrue('Control must be active', control.isActive()); assertFalse('Control must not be focused', control.isFocused()); } // TODO(attila): Find out why this is flaky on FF2/Linux and FF1.5/Win. // function testHandleMouseDownForSelectableControl() { // control.setAllowTextSelection(true); // control.render(sandbox); // assertTrue('preventDefault() must not have been called for control ' + // 'that supports text selection', // fireMouseDownAndFocus(control.getElement())); // assertTrue('Control must be highlighted', control.isHighlighted()); // assertTrue('Control must be active', control.isActive()); // // Expected to fail on IE and Mac Safari 3. IE calls focus handlers // // asynchronously, and Mac Safari 3 doesn't support keyboard focus. // expectedFailures.expectFailureFor(goog.userAgent.IE); // expectedFailures.expectFailureFor(isMacSafari3()); // try { // assertTrue('Control must be focused', control.isFocused()); // } catch (e) { // expectedFailures.handleException(e); // } //} /** * Tests {@link goog.ui.Control#handleMouseUp}. */ function testHandleMouseUp() { control.setActive(true); // Override performActionInternal() for testing purposes. var actionPerformed = false; control.performActionInternal = function() { actionPerformed = true; return true; }; resetEventCount(); control.render(sandbox); var element = control.getElement(); // Verify baseline assumptions. assertTrue('Control must be enabled', control.isEnabled()); assertTrue( 'HOVER must be an auto-state', control.isAutoState(goog.ui.Component.State.HOVER)); assertTrue( 'ACTIVE must be an auto-state', control.isAutoState(goog.ui.Component.State.ACTIVE)); assertFalse( 'Control must not start out highlighted', control.isHighlighted()); assertTrue('Control must start out active', control.isActive()); // Scenario 1: Control is disabled. control.setEnabled(false); goog.testing.events.fireMouseUpEvent(element); assertFalse( 'Disabled control must not highlight on mouseup', control.isHighlighted()); assertFalse('No action must have been performed', actionPerformed); control.setActive(true); control.setEnabled(true); // Scenario 2: HOVER is not an auto-state. control.setAutoStates(goog.ui.Component.State.HOVER, false); goog.testing.events.fireMouseUpEvent(element); assertFalse( 'Control must not highlight on mouseup if HOVER isn\'t an ' + 'auto-state', control.isHighlighted()); assertTrue( 'Action must have been performed even if HOVER isn\'t an ' + 'auto-state', actionPerformed); assertFalse( 'Control must have been deactivated on mouseup even if ' + 'HOVER isn\'t an auto-state', control.isActive()); actionPerformed = false; control.setActive(true); control.setAutoStates(goog.ui.Component.State.HOVER, true); // Scenario 3: Control is not active. control.setActive(false); goog.testing.events.fireMouseUpEvent(element); assertTrue( 'Control must highlight on mouseup, even if inactive', control.isHighlighted()); assertFalse( 'No action must have been performed if control is inactive', actionPerformed); assertFalse( 'Inactive control must remain inactive after mouseup', control.isActive()); control.setHighlighted(false); control.setActive(true); // Scenario 4: performActionInternal() returns false. control.performActionInternal = function() { actionPerformed = true; return false; }; goog.testing.events.fireMouseUpEvent(element); assertTrue( 'Control must highlight on mouseup, even if no action is ' + 'performed', control.isHighlighted()); assertTrue('performActionInternal must have been called', actionPerformed); assertTrue( 'Control must not deactivate if performActionInternal ' + 'returns false', control.isActive()); control.setHighlighted(false); actionPerformed = false; control.performActionInternal = function() { actionPerformed = true; return true; }; // Scenario 5: ACTIVE is not an auto-state. control.setAutoStates(goog.ui.Component.State.ACTIVE, false); goog.testing.events.fireMouseUpEvent(element); assertTrue( 'Control must highlight on mouseup even if ACTIVE isn\'t an ' + 'auto-state', control.isHighlighted()); assertTrue( 'Action must have been performed even if ACTIVE isn\'t an ' + 'auto-state', actionPerformed); assertTrue( 'Control must not have been deactivated on mouseup if ' + 'ACTIVE isn\'t an auto-state', control.isActive()); actionPerformed = false; control.setHighlighted(false); control.setAutoStates(goog.ui.Component.State.ACTIVE, true); // Scenario 6: All is well. goog.testing.events.fireMouseUpEvent(element); assertTrue('Control must highlight on mouseup', control.isHighlighted()); assertTrue('Action must have been performed', actionPerformed); assertFalse('Control must have been deactivated', control.isActive()); } function testDefaultConstructor() { var control = new goog.ui.Control(); assertNull(control.getContent()); } function assertClickSequenceFires(msg) { var actionCount = getEventCount(control, goog.ui.Component.EventType.ACTION); goog.testing.events.fireClickSequence(control.getKeyEventTarget()); assertEquals( msg, actionCount + 1, getEventCount(control, goog.ui.Component.EventType.ACTION)); } function assertIsolatedClickFires(msg) { var actionCount = getEventCount(control, goog.ui.Component.EventType.ACTION); goog.testing.events.fireClickEvent(control.getKeyEventTarget()); assertEquals( msg, actionCount + 1, getEventCount(control, goog.ui.Component.EventType.ACTION)); } function assertIsolatedClickDoesNotFire(msg) { var actionCount = getEventCount(control, goog.ui.Component.EventType.ACTION); goog.testing.events.fireClickEvent(control.getKeyEventTarget()); assertEquals( msg, actionCount, getEventCount(control, goog.ui.Component.EventType.ACTION)); } function testIeMouseEventSequenceSimulator() { control.render(sandbox); // Click sequences and isolated clicks must be handled correctly in any order. assertClickSequenceFires('ACTION event expected after a click sequence'); assertClickSequenceFires( 'ACTION event expected after a second consecutive click sequence'); if (goog.userAgent.IE) { // For some reason in IE8 and perhaps earlier, isolated clicks do not result // a detectable dispatch of an ACTION event, so we'll only assert the // desired handling of isolated clicks in IE9 and higher. if (goog.userAgent.isVersionOrHigher(9)) { assertIsolatedClickFires( 'ACTION event expected after an isolated click immediately ' + 'following a click sequence'); assertIsolatedClickFires( 'ACTION event expected after second consecutive isolated click'); } else { // For IE8-and-lower, fire an isolated click event in preparation for our // final assertion. goog.testing.events.fireClickEvent(control.getKeyEventTarget()); } } else { assertIsolatedClickDoesNotFire( 'No ACTION event expected after an isolated click immediately ' + 'following a click sequence'); assertIsolatedClickDoesNotFire( 'No ACTION event expected after second consecutive isolated click'); } assertClickSequenceFires( 'ACTION event expected after click sequence immediately following ' + 'an isolated click '); } function testIeMouseEventSequenceSimulatorStrictMode() { if (!document.createEvent) { return; } control.render(sandbox); var actionCount = getEventCount(control, goog.ui.Component.EventType.ACTION); var e = document.createEvent('MouseEvents'); e.initMouseEvent( 'click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); control.getElementStrict().dispatchEvent(e); if (goog.userAgent.IE) { assertEquals( 'ACTION event expected after an isolated click', actionCount + 1, getEventCount(control, goog.ui.Component.EventType.ACTION)); } else { assertEquals( 'No ACTION event expected after an isolated click', actionCount, getEventCount(control, goog.ui.Component.EventType.ACTION)); } }