// 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.ControlRendererTest'); goog.setTestOnly('goog.ui.ControlRendererTest'); goog.require('goog.a11y.aria'); goog.require('goog.a11y.aria.Role'); goog.require('goog.a11y.aria.State'); goog.require('goog.dom'); goog.require('goog.dom.NodeType'); goog.require('goog.dom.TagName'); goog.require('goog.dom.classlist'); goog.require('goog.object'); goog.require('goog.style'); goog.require('goog.testing.ExpectedFailures'); goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.jsunit'); goog.require('goog.ui.Component'); goog.require('goog.ui.Control'); goog.require('goog.ui.ControlRenderer'); goog.require('goog.userAgent'); var control, controlRenderer, testRenderer, propertyReplacer; var sandbox; var expectedFailures; function setUpPage() { sandbox = goog.dom.getElement('sandbox'); expectedFailures = new goog.testing.ExpectedFailures(); } /** * A subclass of ControlRenderer that overrides {@code getAriaRole} and * {@code getStructuralCssClass} for testing purposes. * @constructor * @extends {goog.ui.ControlRenderer} */ function TestRenderer() { goog.ui.ControlRenderer.call(this); } goog.inherits(TestRenderer, goog.ui.ControlRenderer); goog.addSingletonGetter(TestRenderer); TestRenderer.CSS_CLASS = 'goog-button'; TestRenderer.IE6_CLASS_COMBINATIONS = [ ['combined', 'goog-base-hover', 'goog-button'], ['combined', 'goog-base-disabled', 'goog-button'], ['combined', 'combined2', 'goog-base-hover', 'goog-base-rtl', 'goog-button'] ]; /** @override */ TestRenderer.prototype.getAriaRole = function() { return goog.a11y.aria.Role.BUTTON; }; /** @override */ TestRenderer.prototype.getCssClass = function() { return TestRenderer.CSS_CLASS; }; /** @override */ TestRenderer.prototype.getStructuralCssClass = function() { return 'goog-base'; }; /** @override */ TestRenderer.prototype.getIe6ClassCombinations = function() { return TestRenderer.IE6_CLASS_COMBINATIONS; }; /** * @return {boolean} Whether we're on Mac Safari 3.x. */ function isMacSafari3() { return goog.userAgent.WEBKIT && goog.userAgent.MAC && !goog.userAgent.isVersionOrHigher('527'); } /** * @return {boolean} Whether we're on IE6 or lower. */ function isIe6() { return goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('7'); } function setUp() { control = new goog.ui.Control('Hello'); controlRenderer = goog.ui.ControlRenderer.getInstance(); testRenderer = TestRenderer.getInstance(); propertyReplacer = new goog.testing.PropertyReplacer(); } function tearDown() { propertyReplacer.reset(); control.dispose(); expectedFailures.handleTearDown(); control = null; controlRenderer = null; testRenderer = null; goog.dom.removeChildren(sandbox); } function testConstructor() { assertNotNull( 'ControlRenderer singleton instance must not be null', controlRenderer); assertNotNull( 'TestRenderer singleton instance must not be null', testRenderer); } function testGetCustomRenderer() { var cssClass = 'special-css-class'; var renderer = goog.ui.ControlRenderer.getCustomRenderer( goog.ui.ControlRenderer, cssClass); assertEquals( 'Renderer should have returned the custom CSS class.', cssClass, renderer.getCssClass()); } function testGetAriaRole() { assertUndefined( 'ControlRenderer\'s ARIA role must be undefined', controlRenderer.getAriaRole()); assertEquals( 'TestRenderer\'s ARIA role must have expected value', goog.a11y.aria.Role.BUTTON, testRenderer.getAriaRole()); } function testCreateDom() { assertHTMLEquals( 'ControlRenderer must create correct DOM', '
Hello
', goog.dom.getOuterHtml(controlRenderer.createDom(control))); assertHTMLEquals( 'TestRenderer must create correct DOM', '
Hello
', goog.dom.getOuterHtml(testRenderer.createDom(control))); } function testGetContentElement() { assertEquals( 'getContentElement() must return its argument', sandbox, controlRenderer.getContentElement(sandbox)); } function testEnableExtraClassName() { // enableExtraClassName() must be a no-op if control has no DOM. controlRenderer.enableExtraClassName(control, 'foo', true); control.createDom(); var element = control.getElement(); controlRenderer.enableExtraClassName(control, 'foo', true); assertSameElements( 'Extra class name must have been added', ['goog-control', 'foo'], goog.dom.classlist.get(element)); controlRenderer.enableExtraClassName(control, 'foo', true); assertSameElements( 'Enabling existing extra class name must be a no-op', ['goog-control', 'foo'], goog.dom.classlist.get(element)); controlRenderer.enableExtraClassName(control, 'bar', false); assertSameElements( 'Disabling nonexistent class name must be a no-op', ['goog-control', 'foo'], goog.dom.classlist.get(element)); controlRenderer.enableExtraClassName(control, 'foo', false); assertSameElements( 'Extra class name must have been removed', ['goog-control'], goog.dom.classlist.get(element)); } function testCanDecorate() { assertTrue('canDecorate() must return true', controlRenderer.canDecorate()); } function testDecorate() { sandbox.innerHTML = '
Hello, world!
'; var foo = goog.dom.getElement('foo'); var element = controlRenderer.decorate(control, foo); assertEquals('decorate() must return its argument', foo, element); assertEquals('Decorated control\'s ID must be set', 'foo', control.getId()); assertTrue( 'Decorated control\'s content must be a text node', control.getContent().nodeType == goog.dom.NodeType.TEXT); assertEquals( 'Decorated control\'s content must have expected value', 'Hello, world!', control.getContent().nodeValue); assertEquals( 'Decorated control\'s state must be as expected', 0x00, control.getState()); assertSameElements( 'Decorated element\'s classes must be as expected', ['goog-control'], goog.dom.classlist.get(element)); } function testDecorateComplexDom() { sandbox.innerHTML = '
Hello,world!
'; var foo = goog.dom.getElement('foo'); var element = controlRenderer.decorate(control, foo); assertEquals('decorate() must return its argument', foo, element); assertEquals('Decorated control\'s ID must be set', 'foo', control.getId()); assertTrue( 'Decorated control\'s content must be an array', goog.isArray(control.getContent())); assertEquals( 'Decorated control\'s content must have expected length', 4, control.getContent().length); assertEquals( 'Decorated control\'s state must be as expected', 0x00, control.getState()); assertSameElements( 'Decorated element\'s classes must be as expected', ['goog-control'], goog.dom.classlist.get(element)); } function testDecorateWithClasses() { sandbox.innerHTML = '
'; var foo = goog.dom.getElement('foo'); control.addClassName('extra'); var element = testRenderer.decorate(control, foo); assertEquals('decorate() must return its argument', foo, element); assertEquals('Decorated control\'s ID must be set', 'foo', control.getId()); assertNull('Decorated control\'s content must be null', control.getContent()); assertEquals( 'Decorated control\'s state must be as expected', goog.ui.Component.State.DISABLED | goog.ui.Component.State.HOVER, control.getState()); assertSameElements( 'Decorated element\'s classes must be as expected', [ 'app', 'extra', 'goog-base', 'goog-base-disabled', 'goog-base-hover', 'goog-button' ], goog.dom.classlist.get(element)); } function testDecorateOptimization() { // Temporarily replace goog.dom.classlist.set(). propertyReplacer.set(goog.dom.classlist, 'set', function() { fail('goog.dom.classlist.set() must not be called'); }); // Since foo has all required classes, goog.dom.classlist.set() must not be // called at all. sandbox.innerHTML = '
Foo
'; controlRenderer.decorate(control, goog.dom.getElement('foo')); // Since bar has all required classes, goog.dom.classlist.set() must not be // called at all. sandbox.innerHTML = '
Bar' + '
'; testRenderer.decorate(control, goog.dom.getElement('bar')); // Since baz has all required classes, goog.dom.classlist.set() must not be // called at all. sandbox.innerHTML = '
Baz
'; testRenderer.decorate(control, goog.dom.getElement('baz')); } function testInitializeDom() { var renderer = new goog.ui.ControlRenderer(); // Replace setRightToLeft(). renderer.setRightToLeft = function() { fail('setRightToLeft() must not be called'); }; // When a control with default render direction enters the document, // setRightToLeft() must not be called. control.setRenderer(renderer); control.render(sandbox); // When a control in the default state (enabled, visible, focusable) // enters the document, it must get a tab index. // Expected to fail on Mac Safari 3, because it doesn't support tab index. expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue( 'Enabled, visible, focusable control must have tab index', goog.dom.isFocusableTabIndex(control.getElement())); } catch (e) { expectedFailures.handleException(e); } } function testInitializeDomDecorated() { var renderer = new goog.ui.ControlRenderer(); // Replace setRightToLeft(). renderer.setRightToLeft = function() { fail('setRightToLeft() must not be called'); }; sandbox.innerHTML = '
Foo
'; // When a control with default render direction enters the document, // setRightToLeft() must not be called. control.setRenderer(renderer); control.decorate(goog.dom.getElement('foo')); // When a control in the default state (enabled, visible, focusable) // enters the document, it must get a tab index. // Expected to fail on Mac Safari 3, because it doesn't support tab index. expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue( 'Enabled, visible, focusable control must have tab index', goog.dom.isFocusableTabIndex(control.getElement())); } catch (e) { expectedFailures.handleException(e); } } function testInitializeDomDisabledBiDi() { var renderer = new goog.ui.ControlRenderer(); // Replace setFocusable(). renderer.setFocusable = function() { fail('setFocusable() must not be called'); }; // When a disabled control enters the document, setFocusable() must not // be called. control.setEnabled(false); control.setRightToLeft(true); control.setRenderer(renderer); control.render(sandbox); // When a right-to-left control enters the document, special stying must // be applied. assertSameElements( 'BiDi control must have right-to-left class', ['goog-control', 'goog-control-disabled', 'goog-control-rtl'], goog.dom.classlist.get(control.getElement())); } function testInitializeDomDisabledBiDiDecorated() { var renderer = new goog.ui.ControlRenderer(); // Replace setFocusable(). renderer.setFocusable = function() { fail('setFocusable() must not be called'); }; sandbox.innerHTML = '
\n' + '
Foo
\n' + '
\n'; // When a disabled control enters the document, setFocusable() must not // be called. control.setRenderer(renderer); control.decorate(goog.dom.getElement('foo')); // When a right-to-left control enters the document, special stying must // be applied. assertSameElements( 'BiDi control must have right-to-left class', ['goog-control', 'goog-control-disabled', 'goog-control-rtl'], goog.dom.classlist.get(control.getElement())); } function testSetAriaRole() { sandbox.innerHTML = '
Foo
Bar
'; var foo = goog.dom.getElement('foo'); assertNotNull(foo); controlRenderer.setAriaRole(foo); assertEvaluatesToFalse( 'The role should be empty.', goog.a11y.aria.getRole(foo)); var bar = goog.dom.getElement('bar'); assertNotNull(bar); testRenderer.setAriaRole(bar); assertEquals( 'Element must have expected ARIA role', goog.a11y.aria.Role.BUTTON, goog.a11y.aria.getRole(bar)); } function testSetAriaStatesHidden() { sandbox.innerHTML = '
Foo
Bar
'; var foo = goog.dom.getElement('foo'); control.setVisible(true); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-hidden.', '', goog.a11y.aria.getState(foo, goog.a11y.aria.State.HIDDEN)); control.setVisible(false); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-hidden.', 'true', goog.a11y.aria.getState(foo, goog.a11y.aria.State.HIDDEN)); } function testSetAriaStatesDisabled() { sandbox.innerHTML = '
Foo
Bar
'; var foo = goog.dom.getElement('foo'); control.setEnabled(true); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-disabled.', '', goog.a11y.aria.getState(foo, goog.a11y.aria.State.DISABLED)); control.setEnabled(false); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-disabled.', 'true', goog.a11y.aria.getState(foo, goog.a11y.aria.State.DISABLED)); } function testSetAriaStatesSelected() { sandbox.innerHTML = '
Foo
Bar
'; var foo = goog.dom.getElement('foo'); control.setSupportedState(goog.ui.Component.State.SELECTED, true); control.setSelected(true); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-selected.', 'true', goog.a11y.aria.getState(foo, goog.a11y.aria.State.SELECTED)); control.setSelected(false); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-selected.', 'false', goog.a11y.aria.getState(foo, goog.a11y.aria.State.SELECTED)); } function testSetAriaStatesChecked() { sandbox.innerHTML = '
Foo
Bar
'; var foo = goog.dom.getElement('foo'); control.setSupportedState(goog.ui.Component.State.CHECKED, true); control.setChecked(true); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-checked.', 'true', goog.a11y.aria.getState(foo, goog.a11y.aria.State.CHECKED)); control.setChecked(false); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-checked.', 'false', goog.a11y.aria.getState(foo, goog.a11y.aria.State.CHECKED)); } function testSetAriaStatesExpanded() { sandbox.innerHTML = '
Foo
Bar
'; var foo = goog.dom.getElement('foo'); control.setSupportedState(goog.ui.Component.State.OPENED, true); control.setOpen(true); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-expanded.', 'true', goog.a11y.aria.getState(foo, goog.a11y.aria.State.EXPANDED)); control.setOpen(false); controlRenderer.setAriaStates(control, foo); assertEquals( 'ControlRenderer did not set aria-expanded.', 'false', goog.a11y.aria.getState(foo, goog.a11y.aria.State.EXPANDED)); } function testSetAllowTextSelection() { sandbox.innerHTML = '
Foo
'; var foo = goog.dom.getElement('foo'); controlRenderer.setAllowTextSelection(foo, false); assertTrue( 'Parent element must be unselectable on all browsers', goog.style.isUnselectable(foo)); if (goog.userAgent.IE || goog.userAgent.OPERA) { assertTrue( 'On IE and Opera, child element must also be unselectable', goog.style.isUnselectable(foo.firstChild)); } else { assertFalse( 'On browsers other than IE and Opera, the child element ' + 'must not be unselectable', goog.style.isUnselectable(foo.firstChild)); } controlRenderer.setAllowTextSelection(foo, true); assertFalse( 'Parent element must be selectable', goog.style.isUnselectable(foo)); assertFalse( 'Child element must be unselectable', goog.style.isUnselectable(foo.firstChild)); } function testSetRightToLeft() { sandbox.innerHTML = '
Foo
Bar
'; var foo = goog.dom.getElement('foo'); controlRenderer.setRightToLeft(foo, true); assertSameElements( 'Element must have right-to-left class applied', ['goog-control-rtl'], goog.dom.classlist.get(foo)); controlRenderer.setRightToLeft(foo, false); assertSameElements( 'Element must not have right-to-left class applied', [], goog.dom.classlist.get(foo)); var bar = goog.dom.getElement('bar'); testRenderer.setRightToLeft(bar, true); assertSameElements( 'Element must have right-to-left class applied', ['goog-base-rtl'], goog.dom.classlist.get(bar)); testRenderer.setRightToLeft(bar, false); assertSameElements( 'Element must not have right-to-left class applied', [], goog.dom.classlist.get(bar)); } function testIsFocusable() { control.render(sandbox); // Expected to fail on Mac Safari 3, because it doesn't support tab index. expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue( 'Control\'s key event target must be focusable', controlRenderer.isFocusable(control)); } catch (e) { expectedFailures.handleException(e); } } function testIsFocusableForNonFocusableControl() { control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.render(sandbox); assertFalse( 'Non-focusable control\'s key event target must not be ' + 'focusable', controlRenderer.isFocusable(control)); } function testIsFocusableForControlWithoutKeyEventTarget() { // Unrendered control has no key event target. assertNull( 'Unrendered control must not have key event target', control.getKeyEventTarget()); assertFalse( 'isFocusable() must return null if no key event target', controlRenderer.isFocusable(control)); } function testSetFocusable() { control.render(sandbox); controlRenderer.setFocusable(control, false); assertFalse( 'Control\'s key event target must not have tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); controlRenderer.setFocusable(control, true); // Expected to fail on Mac Safari 3, because it doesn't support tab index. expectedFailures.expectFailureFor(isMacSafari3()); try { assertTrue( 'Control\'s key event target must have focusable tab index', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); } catch (e) { expectedFailures.handleException(e); } } function testSetFocusableForNonFocusableControl() { control.setSupportedState(goog.ui.Component.State.FOCUSED, false); control.render(sandbox); assertFalse( 'Non-focusable control\'s key event target must not be ' + 'focusable', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); controlRenderer.setFocusable(control, true); assertFalse( 'Non-focusable control\'s key event target must not be ' + 'focusable, even after calling setFocusable(true)', goog.dom.isFocusableTabIndex(control.getKeyEventTarget())); } function testSetVisible() { sandbox.innerHTML = '
Foo
'; var foo = goog.dom.getElement('foo'); assertTrue('Element must be visible', foo.style.display != 'none'); controlRenderer.setVisible(foo, true); assertEquals( 'ControlRenderer did not set aria-hidden.', 'false', goog.a11y.aria.getState(foo, goog.a11y.aria.State.HIDDEN)); assertTrue('Element must still be visible', foo.style.display != 'none'); controlRenderer.setVisible(foo, false); assertEquals( 'ControlRenderer did not set aria-hidden.', 'true', goog.a11y.aria.getState(foo, goog.a11y.aria.State.HIDDEN)); assertTrue('Element must be hidden', foo.style.display == 'none'); } function testSetState() { control.setRenderer(testRenderer); control.createDom(); var element = control.getElement(); assertNotNull(element); assertSameElements( 'Control must have expected class names', ['goog-button', 'goog-base'], goog.dom.classlist.get(element)); assertEquals( 'Control must not have disabled ARIA state', '', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); testRenderer.setState(control, goog.ui.Component.State.DISABLED, true); assertSameElements( 'Control must have disabled class name', ['goog-button', 'goog-base', 'goog-base-disabled'], goog.dom.classlist.get(element)); assertEquals( 'Control must have disabled ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); testRenderer.setState(control, goog.ui.Component.State.DISABLED, false); assertSameElements( 'Control must no longer have disabled class name', ['goog-button', 'goog-base'], goog.dom.classlist.get(element)); assertEquals( 'Control must not have disabled ARIA state', 'false', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); testRenderer.setState(control, 0xFFFFFF, true); assertSameElements( 'Class names must be unchanged for invalid state', ['goog-button', 'goog-base'], goog.dom.classlist.get(element)); } function testUpdateAriaStateDisabled() { control.createDom(); var element = control.getElement(); assertNotNull(element); controlRenderer.updateAriaState( element, goog.ui.Component.State.DISABLED, true); assertEquals( 'Control must have disabled ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); controlRenderer.updateAriaState( element, goog.ui.Component.State.DISABLED, false); assertEquals( 'Control must no longer have disabled ARIA state', 'false', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); } function testSetAriaStatesRender_ariaStateDisabled() { control.setEnabled(false); var renderer = new goog.ui.ControlRenderer(); control.setRenderer(renderer); control.render(sandbox); var element = control.getElement(); assertNotNull(element); assertFalse('Control must be disabled', control.isEnabled()); assertEquals( 'Control must have disabled ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); } function testSetAriaStatesDecorate_ariaStateDisabled() { sandbox.innerHTML = '
'; var element = goog.dom.getElement('foo'); control.setRenderer(testRenderer); control.decorate(element); assertNotNull(element); assertFalse('Control must be disabled', control.isEnabled()); assertEquals( 'Control must have disabled ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); } function testUpdateAriaStateSelected() { control.createDom(); var element = control.getElement(); assertNotNull(element); controlRenderer.updateAriaState( element, goog.ui.Component.State.SELECTED, true); assertEquals( 'Control must have selected ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.SELECTED)); controlRenderer.updateAriaState( element, goog.ui.Component.State.SELECTED, false); assertEquals( 'Control must no longer have selected ARIA state', 'false', goog.a11y.aria.getState(element, goog.a11y.aria.State.SELECTED)); } function testSetAriaStatesRender_ariaStateSelected() { control.setSupportedState(goog.ui.Component.State.SELECTED, true); control.setSelected(true); var renderer = new goog.ui.ControlRenderer(); control.setRenderer(renderer); control.render(sandbox); var element = control.getElement(); assertNotNull(element); assertTrue('Control must be selected', control.isSelected()); assertEquals( 'Control must have selected ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.SELECTED)); } function testSetAriaStatesRender_ariaStateNotSelected() { control.setSupportedState(goog.ui.Component.State.SELECTED, true); var renderer = new goog.ui.ControlRenderer(); control.setRenderer(renderer); control.render(sandbox); var element = control.getElement(); assertNotNull(element); assertFalse('Control must not be selected', control.isSelected()); assertEquals( 'Control must have not-selected ARIA state', 'false', goog.a11y.aria.getState(element, goog.a11y.aria.State.SELECTED)); } function testSetAriaStatesDecorate_ariaStateSelected() { control.setSupportedState(goog.ui.Component.State.SELECTED, true); sandbox.innerHTML = '
'; var element = goog.dom.getElement('foo'); control.setRenderer(controlRenderer); control.decorate(element); assertNotNull(element); assertTrue('Control must be selected', control.isSelected()); assertEquals( 'Control must have selected ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.SELECTED)); } function testUpdateAriaStateChecked() { control.createDom(); var element = control.getElement(); assertNotNull(element); controlRenderer.updateAriaState( element, goog.ui.Component.State.CHECKED, true); assertEquals( 'Control must have checked ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.CHECKED)); controlRenderer.updateAriaState( element, goog.ui.Component.State.CHECKED, false); assertEquals( 'Control must no longer have checked ARIA state', 'false', goog.a11y.aria.getState(element, goog.a11y.aria.State.CHECKED)); } function testSetAriaStatesRender_ariaStateChecked() { control.setSupportedState(goog.ui.Component.State.CHECKED, true); control.setChecked(true); var renderer = new goog.ui.ControlRenderer(); control.setRenderer(renderer); control.render(sandbox); var element = control.getElement(); assertNotNull(element); assertTrue('Control must be checked', control.isChecked()); assertEquals( 'Control must have checked ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.CHECKED)); } function testSetAriaStatesDecorate_ariaStateChecked() { sandbox.innerHTML = '
'; var element = goog.dom.getElement('foo'); control.setSupportedState(goog.ui.Component.State.CHECKED, true); control.decorate(element); assertNotNull(element); assertTrue('Control must be checked', control.isChecked()); assertEquals( 'Control must have checked ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.CHECKED)); } function testUpdateAriaStateOpened() { control.createDom(); var element = control.getElement(); assertNotNull(element); controlRenderer.updateAriaState( element, goog.ui.Component.State.OPENED, true); assertEquals( 'Control must have expanded ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.EXPANDED)); controlRenderer.updateAriaState( element, goog.ui.Component.State.OPENED, false); assertEquals( 'Control must no longer have expanded ARIA state', 'false', goog.a11y.aria.getState(element, goog.a11y.aria.State.EXPANDED)); } function testSetAriaStatesRender_ariaStateOpened() { control.setSupportedState(goog.ui.Component.State.OPENED, true); control.setOpen(true); var renderer = new goog.ui.ControlRenderer(); control.setRenderer(renderer); control.render(sandbox); var element = control.getElement(); assertNotNull(element); assertTrue('Control must be opened', control.isOpen()); assertEquals( 'Control must have expanded ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.EXPANDED)); } function testSetAriaStatesDecorate_ariaStateOpened() { sandbox.innerHTML = '
'; var element = goog.dom.getElement('foo'); control.setSupportedState(goog.ui.Component.State.OPENED, true); control.setRenderer(testRenderer); control.decorate(element); assertNotNull(element); assertTrue('Control must be opened', control.isOpen()); assertEquals( 'Control must have expanded ARIA state', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.EXPANDED)); } function testSetAriaStateRoleNotInMap() { sandbox.innerHTML = '
Hello, world!
'; control.setRenderer(controlRenderer); control.setSupportedState(goog.ui.Component.State.CHECKED, true); var element = goog.dom.getElement('foo'); control.decorate(element); assertEquals( 'Element should have ARIA role option.', goog.a11y.aria.Role.OPTION, goog.a11y.aria.getRole(element)); control.setStateInternal(goog.ui.Component.State.DISABLED, true); controlRenderer.setAriaStates(control, element); assertEquals( 'Element should have aria-disabled true', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); control.setStateInternal(goog.ui.Component.State.CHECKED, true); controlRenderer.setAriaStates(control, element); assertEquals( 'Element should have aria-checked true', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.CHECKED)); } function testSetAriaStateRoleInMapMatches() { sandbox.innerHTML = ''; control.setRenderer(controlRenderer); control.setSupportedState(goog.ui.Component.State.CHECKED, true); var element = goog.dom.getElement('foo'); control.decorate(element); assertEquals( 'Element should have ARIA role checkbox.', goog.a11y.aria.Role.CHECKBOX, goog.a11y.aria.getRole(element)); control.setStateInternal(goog.ui.Component.State.DISABLED, true); controlRenderer.setAriaStates(control, element); assertEquals( 'Element should have aria-disabled true', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); control.setStateInternal(goog.ui.Component.State.CHECKED, true); controlRenderer.setAriaStates(control, element); assertEquals( 'Element should have aria-checked true', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.CHECKED)); } function testSetAriaStateRoleInMapNotMatches() { sandbox.innerHTML = '
Hello, world!
'; control.setRenderer(controlRenderer); control.setSupportedState(goog.ui.Component.State.CHECKED, true); var element = goog.dom.getElement('foo'); control.decorate(element); assertEquals( 'Element should have ARIA role button.', goog.a11y.aria.Role.BUTTON, goog.a11y.aria.getRole(element)); control.setStateInternal(goog.ui.Component.State.DISABLED, true); controlRenderer.setAriaStates(control, element); assertEquals( 'Element should have aria-disabled true', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.DISABLED)); control.setStateInternal(goog.ui.Component.State.CHECKED, true); controlRenderer.setAriaStates(control, element); assertEquals( 'Element should have aria-pressed true', 'true', goog.a11y.aria.getState(element, goog.a11y.aria.State.PRESSED)); assertEquals( 'Element should not have aria-checked', '', goog.a11y.aria.getState(element, goog.a11y.aria.State.CHECKED)); } function testToggleAriaStateMap() { var map = goog.object.create( goog.a11y.aria.Role.BUTTON, goog.a11y.aria.State.PRESSED, goog.a11y.aria.Role.CHECKBOX, goog.a11y.aria.State.CHECKED, goog.a11y.aria.Role.MENU_ITEM, goog.a11y.aria.State.SELECTED, goog.a11y.aria.Role.MENU_ITEM_CHECKBOX, goog.a11y.aria.State.CHECKED, goog.a11y.aria.Role.MENU_ITEM_RADIO, goog.a11y.aria.State.CHECKED, goog.a11y.aria.Role.RADIO, goog.a11y.aria.State.CHECKED, goog.a11y.aria.Role.TAB, goog.a11y.aria.State.SELECTED, goog.a11y.aria.Role.TREEITEM, goog.a11y.aria.State.SELECTED); for (var key in map) { assertTrue( 'Toggle ARIA state map incorrect.', key in goog.ui.ControlRenderer.TOGGLE_ARIA_STATE_MAP_); assertEquals( 'Toggle ARIA state map incorrect.', map[key], goog.ui.ControlRenderer.TOGGLE_ARIA_STATE_MAP_[key]); } } function testSetContent() { goog.dom.setTextContent(sandbox, 'Hello, world!'); controlRenderer.setContent(sandbox, 'Not so fast!'); assertEquals( 'Element must contain expected text value', 'Not so fast!', goog.dom.getTextContent(sandbox)); } function testSetContentNull() { goog.dom.setTextContent(sandbox, 'Hello, world!'); controlRenderer.setContent(sandbox, null); assertEquals( 'Element must have no child nodes', 0, sandbox.childNodes.length); assertEquals( 'Element must contain expected text value', '', goog.dom.getTextContent(sandbox)); } function testSetContentEmpty() { goog.dom.setTextContent(sandbox, 'Hello, world!'); controlRenderer.setContent(sandbox, ''); assertEquals('Element must not have children', 0, sandbox.childNodes.length); assertEquals( 'Element must contain expected text value', '', goog.dom.getTextContent(sandbox)); } function testSetContentWhitespace() { goog.dom.setTextContent(sandbox, 'Hello, world!'); controlRenderer.setContent(sandbox, ' '); assertEquals('Element must have one child', 1, sandbox.childNodes.length); assertEquals( 'Child must be a text node', goog.dom.NodeType.TEXT, sandbox.firstChild.nodeType); assertEquals( 'Element must contain expected text value', ' ', goog.dom.getTextContent(sandbox)); } function testSetContentTextNode() { goog.dom.setTextContent(sandbox, 'Hello, world!'); controlRenderer.setContent(sandbox, document.createTextNode('Text')); assertEquals('Element must have one child', 1, sandbox.childNodes.length); assertEquals( 'Child must be a text node', goog.dom.NodeType.TEXT, sandbox.firstChild.nodeType); assertEquals( 'Element must contain expected text value', 'Text', goog.dom.getTextContent(sandbox)); } function testSetContentElementNode() { goog.dom.setTextContent(sandbox, 'Hello, world!'); controlRenderer.setContent( sandbox, goog.dom.createDom(goog.dom.TagName.DIV, {id: 'foo'}, 'Foo')); assertEquals('Element must have one child', 1, sandbox.childNodes.length); assertEquals( 'Child must be an element node', goog.dom.NodeType.ELEMENT, sandbox.firstChild.nodeType); assertHTMLEquals( 'Element must contain expected HTML', '
Foo
', sandbox.innerHTML); } function testSetContentArray() { goog.dom.setTextContent(sandbox, 'Hello, world!'); controlRenderer.setContent( sandbox, ['Hello, ', goog.dom.createDom(goog.dom.TagName.B, null, 'world'), '!']); assertEquals( 'Element must have three children', 3, sandbox.childNodes.length); assertEquals( '1st child must be a text node', goog.dom.NodeType.TEXT, sandbox.childNodes[0].nodeType); assertEquals( '2nd child must be an element', goog.dom.NodeType.ELEMENT, sandbox.childNodes[1].nodeType); assertEquals( '3rd child must be a text node', goog.dom.NodeType.TEXT, sandbox.childNodes[2].nodeType); assertHTMLEquals( 'Element must contain expected HTML', 'Hello, world!', sandbox.innerHTML); } function testSetContentNodeList() { goog.dom.setTextContent(sandbox, 'Hello, world!'); var div = goog.dom.createDom( goog.dom.TagName.DIV, null, 'Hello, ', goog.dom.createDom(goog.dom.TagName.B, null, 'world'), '!'); controlRenderer.setContent(sandbox, div.childNodes); assertEquals( 'Element must have three children', 3, sandbox.childNodes.length); assertEquals( '1st child must be a text node', goog.dom.NodeType.TEXT, sandbox.childNodes[0].nodeType); assertEquals( '2nd child must be an element', goog.dom.NodeType.ELEMENT, sandbox.childNodes[1].nodeType); assertEquals( '3rd child must be a text node', goog.dom.NodeType.TEXT, sandbox.childNodes[2].nodeType); assertHTMLEquals( 'Element must contain expected HTML', 'Hello, world!', sandbox.innerHTML); } function testGetKeyEventTarget() { assertNull( 'Key event target for unrendered control must be null', controlRenderer.getKeyEventTarget(control)); control.createDom(); assertEquals( 'Key event target for rendered control must be its element', control.getElement(), controlRenderer.getKeyEventTarget(control)); } function testGetCssClass() { assertEquals( 'ControlRenderer\'s CSS class must have expected value', goog.ui.ControlRenderer.CSS_CLASS, controlRenderer.getCssClass()); assertEquals( 'TestRenderer\'s CSS class must have expected value', TestRenderer.CSS_CLASS, testRenderer.getCssClass()); } function testGetStructuralCssClass() { assertEquals( 'ControlRenderer\'s structural class must be its CSS class', controlRenderer.getCssClass(), controlRenderer.getStructuralCssClass()); assertEquals( 'TestRenderer\'s structural class must have expected value', 'goog-base', testRenderer.getStructuralCssClass()); } function testGetClassNames() { // These tests use assertArrayEquals, because the order is significant. assertArrayEquals( 'ControlRenderer must return expected class names ' + 'in the expected order', ['goog-control'], controlRenderer.getClassNames(control)); assertArrayEquals( 'TestRenderer must return expected class names ' + 'in the expected order', ['goog-button', 'goog-base'], testRenderer.getClassNames(control)); } function testGetClassNamesForControlWithState() { control.setStateInternal( goog.ui.Component.State.HOVER | goog.ui.Component.State.ACTIVE); // These tests use assertArrayEquals, because the order is significant. assertArrayEquals( 'ControlRenderer must return expected class names ' + 'in the expected order', ['goog-control', 'goog-control-hover', 'goog-control-active'], controlRenderer.getClassNames(control)); assertArrayEquals( 'TestRenderer must return expected class names ' + 'in the expected order', ['goog-button', 'goog-base', 'goog-base-hover', 'goog-base-active'], testRenderer.getClassNames(control)); } function testGetClassNamesForControlWithExtraClassNames() { control.addClassName('foo'); control.addClassName('bar'); // These tests use assertArrayEquals, because the order is significant. assertArrayEquals( 'ControlRenderer must return expected class names ' + 'in the expected order', ['goog-control', 'foo', 'bar'], controlRenderer.getClassNames(control)); assertArrayEquals( 'TestRenderer must return expected class names ' + 'in the expected order', ['goog-button', 'goog-base', 'foo', 'bar'], testRenderer.getClassNames(control)); } function testGetClassNamesForControlWithStateAndExtraClassNames() { control.setStateInternal( goog.ui.Component.State.HOVER | goog.ui.Component.State.ACTIVE); control.addClassName('foo'); control.addClassName('bar'); // These tests use assertArrayEquals, because the order is significant. assertArrayEquals( 'ControlRenderer must return expected class names ' + 'in the expected order', [ 'goog-control', 'goog-control-hover', 'goog-control-active', 'foo', 'bar' ], controlRenderer.getClassNames(control)); assertArrayEquals( 'TestRenderer must return expected class names ' + 'in the expected order', [ 'goog-button', 'goog-base', 'goog-base-hover', 'goog-base-active', 'foo', 'bar' ], testRenderer.getClassNames(control)); } function testGetClassNamesForState() { // These tests use assertArrayEquals, because the order is significant. assertArrayEquals( 'ControlRenderer must return expected class names ' + 'in the expected order', ['goog-control-hover', 'goog-control-checked'], controlRenderer.getClassNamesForState( goog.ui.Component.State.HOVER | goog.ui.Component.State.CHECKED)); assertArrayEquals( 'TestRenderer must return expected class names ' + 'in the expected order', ['goog-base-hover', 'goog-base-checked'], testRenderer.getClassNamesForState( goog.ui.Component.State.HOVER | goog.ui.Component.State.CHECKED)); } function testGetClassForState() { var renderer = new goog.ui.ControlRenderer(); assertUndefined( 'State-to-class map must not exist until first use', renderer.classByState_); assertEquals( 'Renderer must return expected class name for SELECTED', 'goog-control-selected', renderer.getClassForState(goog.ui.Component.State.SELECTED)); assertUndefined( 'Renderer must return undefined for invalid state', renderer.getClassForState('foo')); } function testGetStateFromClass() { var renderer = new goog.ui.ControlRenderer(); assertUndefined( 'Class-to-state map must not exist until first use', renderer.stateByClass_); assertEquals( 'Renderer must return expected state', goog.ui.Component.State.SELECTED, renderer.getStateFromClass('goog-control-selected')); assertEquals( 'Renderer must return 0x00 for unknown class', 0x00, renderer.getStateFromClass('goog-control-annoyed')); } function testIe6ClassCombinationsCreateDom() { control.setRenderer(testRenderer); control.enableClassName('combined', true); control.createDom(); var element = control.getElement(); testRenderer.setState(control, goog.ui.Component.State.DISABLED, true); var expectedClasses = ['combined', 'goog-base', 'goog-base-disabled', 'goog-button']; if (isIe6()) { assertSameElements( 'IE6 and lower should have one combined class', expectedClasses.concat(['combined_goog-base-disabled_goog-button']), goog.dom.classlist.get(element)); } else { assertSameElements( 'Non IE6 browsers should not have a combined class', expectedClasses, goog.dom.classlist.get(element)); } testRenderer.setState(control, goog.ui.Component.State.DISABLED, false); testRenderer.setState(control, goog.ui.Component.State.HOVER, true); var expectedClasses = ['combined', 'goog-base', 'goog-base-hover', 'goog-button']; if (isIe6()) { assertSameElements( 'IE6 and lower should have one combined class', expectedClasses.concat(['combined_goog-base-hover_goog-button']), goog.dom.classlist.get(element)); } else { assertSameElements( 'Non IE6 browsers should not have a combined class', expectedClasses, goog.dom.classlist.get(element)); } testRenderer.setRightToLeft(element, true); testRenderer.enableExtraClassName(control, 'combined2', true); var expectedClasses = [ 'combined', 'combined2', 'goog-base', 'goog-base-hover', 'goog-base-rtl', 'goog-button' ]; if (isIe6()) { assertSameElements( 'IE6 and lower should have two combined class', expectedClasses.concat([ 'combined_goog-base-hover_goog-button', 'combined_combined2_goog-base-hover_goog-base-rtl_goog-button' ]), goog.dom.classlist.get(element)); } else { assertSameElements( 'Non IE6 browsers should not have a combined class', expectedClasses, goog.dom.classlist.get(element)); } } function testIe6ClassCombinationsDecorate() { sandbox.innerHTML = '
'; var foo = goog.dom.getElement('foo'); var element = testRenderer.decorate(control, foo); var expectedClasses = ['combined', 'goog-base', 'goog-base-hover', 'goog-button']; if (isIe6()) { assertSameElements( 'IE6 and lower should have one combined class', expectedClasses.concat(['combined_goog-base-hover_goog-button']), goog.dom.classlist.get(element)); } else { assertSameElements( 'Non IE6 browsers should not have a combined class', expectedClasses, goog.dom.classlist.get(element)); } }