// Copyright 2009 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. /** * @fileoverview Shared code for dom_test.html and dom_quirks_test.html. */ goog.provide('goog.dom.dom_test'); goog.require('goog.dom'); goog.require('goog.dom.DomHelper'); goog.require('goog.dom.NodeType'); goog.require('goog.dom.TagName'); goog.require('goog.object'); goog.require('goog.testing.asserts'); goog.require('goog.userAgent'); goog.require('goog.userAgent.product'); goog.require('goog.userAgent.product.isVersion'); goog.setTestOnly('dom_test'); var $ = goog.dom.getElement; var divForTestingScrolling; var myIframe; var myIframeDoc; function setUpPage() { divForTestingScrolling = document.createElement('div'); divForTestingScrolling.style.width = '5000px'; divForTestingScrolling.style.height = '5000px'; document.body.appendChild(divForTestingScrolling); // Setup for the iframe myIframe = $('myIframe'); myIframeDoc = goog.dom.getFrameContentDocument( /** @type {HTMLIFrameElement} */ (myIframe)); // Set up document for iframe: total height of elements in document is 65 // If the elements are not create like below, IE will get a wrong height for // the document. myIframeDoc.open(); // Make sure we progate the compat mode myIframeDoc.write((goog.dom.isCss1CompatMode() ? '' : '') + '' + '
' + 'hello world
' + '
' + 'hello world
'); myIframeDoc.close(); } function tearDownPage() { document.body.removeChild(divForTestingScrolling); } function tearDown() { window.scrollTo(0, 0); } function testDom() { assert('Dom library exists', typeof goog.dom != 'undefined'); } function testGetElement() { var el = $('testEl'); assertEquals('Should be able to get id', el.id, 'testEl'); assertEquals($, goog.dom.getElement); assertEquals(goog.dom.$, goog.dom.getElement); } function testGetElementsByTagNameAndClass() { assertEquals('Should get 6 spans', goog.dom.getElementsByTagNameAndClass('span').length, 6); assertEquals('Should get 6 spans', goog.dom.getElementsByTagNameAndClass('SPAN').length, 6); assertEquals('Should get 3 spans', goog.dom.getElementsByTagNameAndClass('span', 'test1').length, 3); assertEquals('Should get 1 span', goog.dom.getElementsByTagNameAndClass('span', 'test2').length, 1); assertEquals('Should get 1 span', goog.dom.getElementsByTagNameAndClass('SPAN', 'test2').length, 1); assertEquals('Should get lots of elements', goog.dom.getElementsByTagNameAndClass().length, document.getElementsByTagName('*').length); assertEquals('Should get 1 span', goog.dom.getElementsByTagNameAndClass('span', null, $('testEl')).length, 1); // '*' as the tag name should be equivalent to all tags var container = goog.dom.getElement('span-container'); assertEquals(5, goog.dom.getElementsByTagNameAndClass('*', undefined, container).length); assertEquals(3, goog.dom.getElementsByTagNameAndClass('*', 'test1', container).length); assertEquals(1, goog.dom.getElementsByTagNameAndClass('*', 'test2', container).length); // Some version of WebKit have problems with mixed-case class names assertEquals(1, goog.dom.getElementsByTagNameAndClass( undefined, 'mixedCaseClass').length); // Make sure that out of bounds indices are OK assertUndefined( goog.dom.getElementsByTagNameAndClass(undefined, 'noSuchClass')[0]); assertEquals(goog.dom.getElementsByTagNameAndClass, goog.dom.getElementsByTagNameAndClass); } function testGetElementsByClass() { assertEquals(3, goog.dom.getElementsByClass('test1').length); assertEquals(1, goog.dom.getElementsByClass('test2').length); assertEquals(0, goog.dom.getElementsByClass('nonexistant').length); var container = goog.dom.getElement('span-container'); assertEquals(3, goog.dom.getElementsByClass('test1', container).length); } function testGetElementByClass() { assertNotNull(goog.dom.getElementByClass('test1')); assertNotNull(goog.dom.getElementByClass('test2')); // assertNull(goog.dom.getElementByClass('nonexistant')); var container = goog.dom.getElement('span-container'); assertNotNull(goog.dom.getElementByClass('test1', container)); } function testSetProperties() { var attrs = {'name': 'test3', 'title': 'A title', 'random': 'woop'}; var el = $('testEl'); var res = goog.dom.setProperties(el, attrs); assertEquals('Should be equal', el.name, 'test3'); assertEquals('Should be equal', el.title, 'A title'); assertEquals('Should be equal', el.random, 'woop'); } function testSetPropertiesDirectAttributeMap() { var attrs = {'usemap': '#myMap'}; var el = goog.dom.createDom('img'); var res = goog.dom.setProperties(el, attrs); assertEquals('Should be equal', '#myMap', el.getAttribute('usemap')); } function testSetPropertiesAria() { var attrs = { 'aria-hidden': 'true', 'aria-label': 'This is a label', 'role': 'presentation' }; var el = goog.dom.createDom('div'); goog.dom.setProperties(el, attrs); assertEquals('Should be equal', 'true', el.getAttribute('aria-hidden')); assertEquals('Should be equal', 'This is a label', el.getAttribute('aria-label')); assertEquals('Should be equal', 'presentation', el.getAttribute('role')); } function testSetPropertiesData() { var attrs = { 'data-tooltip': 'This is a tooltip', 'data-tooltip-delay': '100' }; var el = goog.dom.createDom('div'); goog.dom.setProperties(el, attrs); assertEquals('Should be equal', 'This is a tooltip', el.getAttribute('data-tooltip')); assertEquals('Should be equal', '100', el.getAttribute('data-tooltip-delay')); } function testSetTableProperties() { var attrs = { 'style': 'padding-left: 10px;', 'class': 'mytestclass', 'height': '101', 'cellpadding': '15' }; var el = $('testTable1'); var res = goog.dom.setProperties(el, attrs); assertEquals('Should be equal', el.style.paddingLeft, '10px'); assertEquals('Should be equal', el.className, 'mytestclass'); assertEquals('Should be equal', el.getAttribute('height'), '101'); assertEquals('Should be equal', el.cellPadding, '15'); } function testGetViewportSize() { // TODO: This is failing in the test runner now, fix later. //var dims = getViewportSize(); //assertNotUndefined('Should be defined at least', dims.width); //assertNotUndefined('Should be defined at least', dims.height); } function testGetViewportSizeInIframe() { var iframe = /** @type {HTMLIFrameElement} */ (goog.dom.getElement('iframe')); var contentDoc = goog.dom.getFrameContentDocument(iframe); contentDoc.write(''); var outerSize = goog.dom.getViewportSize(); var innerSize = (new goog.dom.DomHelper(contentDoc)).getViewportSize(); assert('Viewport sizes must not match', innerSize.width != outerSize.width); } function testGetDocumentHeightInIframe() { var doc = goog.dom.getDomHelper(myIframeDoc).getDocument(); var height = goog.dom.getDomHelper(myIframeDoc).getDocumentHeight(); // Broken in webkit quirks mode and in IE8+ if ((goog.dom.isCss1CompatMode_(doc) || !goog.userAgent.WEBKIT) && !isIE8OrHigher()) { assertEquals('height should be 65', 42 + 23, height); } } function testCreateDom() { var el = goog.dom.$dom('div', { style: 'border: 1px solid black; width: 50%; background-color: #EEE;', onclick: "alert('woo')" }, goog.dom.$dom('p', {style: 'font: normal 12px arial; color: red; '}, 'Para 1'), goog.dom.$dom('p', {style: 'font: bold 18px garamond; color: blue; '}, 'Para 2'), goog.dom.$dom('p', {style: 'font: normal 24px monospace; color: green'}, 'Para 3 ', goog.dom.$dom('a', { name: 'link', href: 'http://bbc.co.uk' }, 'has a link'), ', how cool is this?')); assertEquals('Tagname should be a DIV', 'DIV', el.tagName); assertEquals('Style width should be 50%', '50%', el.style.width); assertEquals('first child is a P tag', 'P', el.childNodes[0].tagName); assertEquals('second child .innerHTML', 'Para 2', el.childNodes[1].innerHTML); assertEquals(goog.dom.$dom, goog.dom.createDom); } function testCreateDomNoChildren() { var el; // Test unspecified children. el = goog.dom.$dom('div'); assertNull('firstChild should be null', el.firstChild); // Test null children. el = goog.dom.$dom('div', null, null); assertNull('firstChild should be null', el.firstChild); // Test empty array of children. el = goog.dom.$dom('div', null, []); assertNull('firstChild should be null', el.firstChild); } function testCreateDomAcceptsArray() { var items = [ goog.dom.$dom('li', {}, 'Item 1'), goog.dom.$dom('li', {}, 'Item 2') ]; var ul = goog.dom.$dom('ul', {}, items); assertEquals('List should have two children', 2, ul.childNodes.length); assertEquals('First child should be an LI tag', 'LI', ul.firstChild.tagName); assertEquals('Item 1', ul.childNodes[0].innerHTML); assertEquals('Item 2', ul.childNodes[1].innerHTML); } function testCreateDomStringArg() { var el; // Test string arg. el = goog.dom.$dom('div', null, 'Hello'); assertEquals('firstChild should be a text node', goog.dom.NodeType.TEXT, el.firstChild.nodeType); assertEquals('firstChild should have node value "Hello"', 'Hello', el.firstChild.nodeValue); // Test text node arg. el = goog.dom.$dom('div', null, goog.dom.createTextNode('World')); assertEquals('firstChild should be a text node', goog.dom.NodeType.TEXT, el.firstChild.nodeType); assertEquals('firstChild should have node value "World"', 'World', el.firstChild.nodeValue); } function testCreateDomNodeListArg() { var el; var emptyElem = goog.dom.$dom('div'); var simpleElem = goog.dom.$dom('div', null, 'Hello, world!'); var complexElem = goog.dom.$dom('div', null, 'Hello, ', goog.dom.$dom('b', null, 'world'), goog.dom.createTextNode('!')); // Test empty node list. el = goog.dom.$dom('div', null, emptyElem.childNodes); assertNull('emptyElem.firstChild should be null', emptyElem.firstChild); assertNull('firstChild should be null', el.firstChild); // Test simple node list. el = goog.dom.$dom('div', null, simpleElem.childNodes); assertNull('simpleElem.firstChild should be null', simpleElem.firstChild); assertEquals('firstChild should be a text node with value "Hello, world!"', 'Hello, world!', el.firstChild.nodeValue); // Test complex node list. el = goog.dom.$dom('div', null, complexElem.childNodes); assertNull('complexElem.firstChild should be null', complexElem.firstChild); assertEquals('Element should have 3 child nodes', 3, el.childNodes.length); assertEquals('childNodes[0] should be a text node with value "Hello, "', 'Hello, ', el.childNodes[0].nodeValue); assertEquals('childNodes[1] should be an element node with tagName "B"', 'B', el.childNodes[1].tagName); assertEquals('childNodes[2] should be a text node with value "!"', '!', el.childNodes[2].nodeValue); } function testCreateDomWithTypeAttribute() { var el = goog.dom.createDom('button', {'type': 'reset', 'id': 'cool-button'}, 'Cool button'); assertNotNull('Button with type attribute was created successfully', el); assertEquals('Button has correct type attribute', 'reset', el.type); assertEquals('Button has correct id', 'cool-button', el.id); } function testCreateDomWithClassList() { var el = goog.dom.createDom('div', ['foo', 'bar']); assertEquals('foo bar', el.className); el = goog.dom.createDom('div', ['foo', 'foo']); assertEquals('foo', el.className); } function testContains() { assertTrue('HTML should contain BODY', goog.dom.contains( document.documentElement, document.body)); assertTrue('Document should contain BODY', goog.dom.contains( document, document.body)); var d = goog.dom.$dom('p', null, 'A paragraph'); var t = d.firstChild; assertTrue('Same element', goog.dom.contains(d, d)); assertTrue('Same text', goog.dom.contains(t, t)); assertTrue('Nested text', goog.dom.contains(d, t)); assertFalse('Nested text, reversed', goog.dom.contains(t, d)); assertFalse('Disconnected element', goog.dom.contains( document, d)); goog.dom.appendChild(document.body, d); assertTrue('Connected element', goog.dom.contains( document, d)); goog.dom.removeNode(d); } function testCreateDomWithClassName() { var el = goog.dom.$dom('div', 'cls'); assertNull('firstChild should be null', el.firstChild); assertEquals('Tagname should be a DIV', 'DIV', el.tagName); assertEquals('ClassName should be cls', 'cls', el.className); el = goog.dom.$dom('div', ''); assertEquals('ClassName should be empty', '', el.className); } function testCompareNodeOrder() { var b1 = $('b1'); var b2 = $('b2'); var p2 = $('p2'); assertEquals('equal nodes should compare to 0', 0, goog.dom.compareNodeOrder(b1, b1)); assertTrue('parent should come before child', goog.dom.compareNodeOrder(p2, b1) < 0); assertTrue('child should come after parent', goog.dom.compareNodeOrder(b1, p2) > 0); assertTrue('parent should come before text child', goog.dom.compareNodeOrder(b1, b1.firstChild) < 0); assertTrue('text child should come after parent', goog.dom.compareNodeOrder( b1.firstChild, b1) > 0); assertTrue('first sibling should come before second', goog.dom.compareNodeOrder(b1, b2) < 0); assertTrue('second sibling should come after first', goog.dom.compareNodeOrder(b2, b1) > 0); assertTrue('text node after cousin element returns correct value', goog.dom.compareNodeOrder(b1.nextSibling, b1) > 0); assertTrue('text node before cousin element returns correct value', goog.dom.compareNodeOrder(b1, b1.nextSibling) < 0); assertTrue('text node is before once removed cousin element', goog.dom.compareNodeOrder(b1.firstChild, b2) < 0); assertTrue('once removed cousin element is before text node', goog.dom.compareNodeOrder(b2, b1.firstChild) > 0); assertTrue('text node is after once removed cousin text node', goog.dom.compareNodeOrder(b1.nextSibling, b1.firstChild) > 0); assertTrue('once removed cousin text node is before text node', goog.dom.compareNodeOrder(b1.firstChild, b1.nextSibling) < 0); assertTrue('first text node is before second text node', goog.dom.compareNodeOrder(b1.previousSibling, b1.nextSibling) < 0); assertTrue('second text node is after first text node', goog.dom.compareNodeOrder(b1.nextSibling, b1.previousSibling) > 0); assertTrue('grandchild is after grandparent', goog.dom.compareNodeOrder(b1.firstChild, b1.parentNode) > 0); assertTrue('grandparent is after grandchild', goog.dom.compareNodeOrder(b1.parentNode, b1.firstChild) < 0); assertTrue('grandchild is after grandparent', goog.dom.compareNodeOrder(b1.firstChild, b1.parentNode) > 0); assertTrue('grandparent is after grandchild', goog.dom.compareNodeOrder(b1.parentNode, b1.firstChild) < 0); assertTrue('second cousins compare correctly', goog.dom.compareNodeOrder(b1.firstChild, b2.firstChild) < 0); assertTrue('second cousins compare correctly in reverse', goog.dom.compareNodeOrder(b2.firstChild, b1.firstChild) > 0); assertTrue('testEl2 is after testEl', goog.dom.compareNodeOrder($('testEl2'), $('testEl')) > 0); assertTrue('testEl is before testEl2', goog.dom.compareNodeOrder($('testEl'), $('testEl2')) < 0); var p = $('order-test'); var text1 = document.createTextNode('1'); p.appendChild(text1); var text2 = document.createTextNode('1'); p.appendChild(text2); assertEquals('Equal text nodes should compare to 0', 0, goog.dom.compareNodeOrder(text1, text1)); assertTrue('First text node is before second', goog.dom.compareNodeOrder(text1, text2) < 0); assertTrue('Second text node is after first', goog.dom.compareNodeOrder(text2, text1) > 0); assertTrue('Late text node is after b1', goog.dom.compareNodeOrder(text1, $('b1')) > 0); assertTrue('Document node is before non-document node', goog.dom.compareNodeOrder(document, b1) < 0); assertTrue('Non-document node is after document node', goog.dom.compareNodeOrder(b1, document) > 0); } function testFindCommonAncestor() { var b1 = $('b1'); var b2 = $('b2'); var p1 = $('p1'); var p2 = $('p2'); var testEl2 = $('testEl2'); assertNull('findCommonAncestor() = null', goog.dom.findCommonAncestor()); assertEquals('findCommonAncestor(b1) = b1', b1, goog.dom.findCommonAncestor(b1)); assertEquals('findCommonAncestor(b1, b1) = b1', b1, goog.dom.findCommonAncestor(b1, b1)); assertEquals('findCommonAncestor(b1, b2) = p2', p2, goog.dom.findCommonAncestor(b1, b2)); assertEquals('findCommonAncestor(p1, b2) = body', document.body, goog.dom.findCommonAncestor(p1, b2)); assertEquals('findCommonAncestor(testEl2, b1, b2, p1, p2) = body', document.body, goog.dom.findCommonAncestor(testEl2, b1, b2, p1, p2)); var outOfDoc = document.createElement('div'); assertNull('findCommonAncestor(outOfDoc, b1) = null', goog.dom.findCommonAncestor(outOfDoc, b1)); } function testRemoveNode() { var b = document.createElement('b'); var el = $('p1'); el.appendChild(b); goog.dom.removeNode(b); assertTrue('b should have been removed', el.lastChild != b); } function testReplaceNode() { var n = $('toReplace'); var previousSibling = n.previousSibling; var goodNode = goog.dom.createDom('div', {'id': 'goodReplaceNode'}); goog.dom.replaceNode(goodNode, n); assertEquals('n should have been replaced', previousSibling.nextSibling, goodNode); assertNull('n should no longer be in the DOM tree', $('toReplace')); var badNode = goog.dom.createDom('div', {'id': 'badReplaceNode'}); goog.dom.replaceNode(badNode, n); assertNull('badNode should not be in the DOM tree', $('badReplaceNode')); } function testAppendChildAt() { var parent = $('p2'); var origNumChildren = parent.childNodes.length; var child1 = document.createElement('div'); goog.dom.insertChildAt(parent, child1, origNumChildren); assertEquals(origNumChildren + 1, parent.childNodes.length); var child2 = document.createElement('div'); goog.dom.insertChildAt(parent, child2, origNumChildren + 42); assertEquals(origNumChildren + 2, parent.childNodes.length); var child3 = document.createElement('div'); goog.dom.insertChildAt(parent, child3, 0); assertEquals(origNumChildren + 3, parent.childNodes.length); var child4 = document.createElement('div'); goog.dom.insertChildAt(parent, child3, 2); assertEquals(origNumChildren + 3, parent.childNodes.length); parent.removeChild(child1); parent.removeChild(child2); parent.removeChild(child3); var emptyParentNotInDocument = document.createElement('div'); goog.dom.insertChildAt(emptyParentNotInDocument, child1, 0); assertEquals(1, emptyParentNotInDocument.childNodes.length); } function testFlattenElement() { var text = document.createTextNode('Text'); var br = document.createElement('br'); var span = goog.dom.createDom('span', null, text, br); assertEquals('span should have 2 children', 2, span.childNodes.length); var el = $('p1'); el.appendChild(span); var ret = goog.dom.flattenElement(span); assertTrue('span should have been removed', el.lastChild != span); assertFalse('span should have no parent', !!span.parentNode && span.parentNode.nodeType != goog.dom.NodeType.DOCUMENT_FRAGMENT); assertEquals('span should have no children', 0, span.childNodes.length); assertEquals('Last child of p should be br', br, el.lastChild); assertEquals('Previous sibling of br should be text', text, br.previousSibling); var outOfDoc = goog.dom.createDom('span', null, '1 child'); // Should do nothing. goog.dom.flattenElement(outOfDoc); assertEquals('outOfDoc should still have 1 child', 1, outOfDoc.childNodes.length); } function testIsNodeLike() { assertTrue('document should be node like', goog.dom.isNodeLike(document)); assertTrue('document.body should be node like', goog.dom.isNodeLike(document.body)); assertTrue('a text node should be node like', goog.dom.isNodeLike( document.createTextNode(''))); assertFalse('null should not be node like', goog.dom.isNodeLike(null)); assertFalse('a string should not be node like', goog.dom.isNodeLike('abcd')); assertTrue('custom object should be node like', goog.dom.isNodeLike({nodeType: 1})); } function testIsElement() { assertFalse('document is not an element', goog.dom.isElement(document)); assertTrue('document.body is an element', goog.dom.isElement(document.body)); assertFalse('a text node is not an element', goog.dom.isElement( document.createTextNode(''))); assertTrue('an element created with createElement() is an element', goog.dom.isElement(document.createElement('a'))); assertFalse('null is not an element', goog.dom.isElement(null)); assertFalse('a string is not an element', goog.dom.isElement('abcd')); assertTrue('custom object is an element', goog.dom.isElement({nodeType: 1})); assertFalse('custom non-element object is a not an element', goog.dom.isElement({someProperty: 'somevalue'})); } function testIsWindow() { var global = goog.global; var frame = window.frames['frame']; var otherWindow = window.open('', 'blank'); var object = {window: goog.global}; var nullVar = null; var notDefined; try { // Use try/finally to ensure that we clean up the window we open, even if an // assertion fails or something else goes wrong. assertTrue('global object in HTML context should be a window', goog.dom.isWindow(goog.global)); assertTrue('iframe window should be a window', goog.dom.isWindow(frame)); if (otherWindow) { assertTrue('other window should be a window', goog.dom.isWindow(otherWindow)); } assertFalse('object should not be a window', goog.dom.isWindow(object)); assertFalse('null should not be a window', goog.dom.isWindow(nullVar)); assertFalse('undefined should not be a window', goog.dom.isWindow(notDefined)); } finally { if (otherWindow) { otherWindow.close(); } } } function testGetOwnerDocument() { assertEquals(goog.dom.getOwnerDocument($('p1')), document); assertEquals(goog.dom.getOwnerDocument(document.body), document); assertEquals(goog.dom.getOwnerDocument(document.documentElement), document); } function testDomHelper() { var x = new goog.dom.DomHelper(window.frames['frame'].document); assertTrue('Should have some HTML', x.getDocument().body.innerHTML.length > 0); } function testGetFirstElementChild() { var p2 = $('p2'); var b1 = goog.dom.getFirstElementChild(p2); assertNotNull('First element child of p2 should not be null', b1); assertEquals('First element child is b1', 'b1', b1.id); var c = goog.dom.getFirstElementChild(b1); assertNull('First element child of b1 should be null', c); // Test with an undefined firstElementChild attribute. var b2 = $('b2'); var mockP2 = { childNodes: [b1, b2], firstChild: b1, firstElementChild: undefined }; b1 = goog.dom.getFirstElementChild(mockP2); assertNotNull('First element child of mockP2 should not be null', b1); assertEquals('First element child is b1', 'b1', b1.id); } function testGetLastElementChild() { var p2 = $('p2'); var b2 = goog.dom.getLastElementChild(p2); assertNotNull('Last element child of p2 should not be null', b2); assertEquals('Last element child is b2', 'b2', b2.id); var c = goog.dom.getLastElementChild(b2); assertNull('Last element child of b2 should be null', c); // Test with an undefined lastElementChild attribute. var b1 = $('b1'); var mockP2 = { childNodes: [b1, b2], lastChild: b2, lastElementChild: undefined }; b2 = goog.dom.getLastElementChild(mockP2); assertNotNull('Last element child of mockP2 should not be null', b2); assertEquals('Last element child is b2', 'b2', b2.id); } function testGetNextElementSibling() { var b1 = $('b1'); var b2 = goog.dom.getNextElementSibling(b1); assertNotNull('Next element sibling of b1 should not be null', b1); assertEquals('Next element sibling is b2', 'b2', b2.id); var c = goog.dom.getNextElementSibling(b2); assertNull('Next element sibling of b2 should be null', c); // Test with an undefined nextElementSibling attribute. var mockB1 = { nextSibling: b2, nextElementSibling: undefined }; b2 = goog.dom.getNextElementSibling(mockB1); assertNotNull('Next element sibling of mockB1 should not be null', b1); assertEquals('Next element sibling is b2', 'b2', b2.id); } function testGetPreviousElementSibling() { var b2 = $('b2'); var b1 = goog.dom.getPreviousElementSibling(b2); assertNotNull('Previous element sibling of b2 should not be null', b1); assertEquals('Previous element sibling is b1', 'b1', b1.id); var c = goog.dom.getPreviousElementSibling(b1); assertNull('Previous element sibling of b1 should be null', c); // Test with an undefined previousElementSibling attribute. var mockB2 = { previousSibling: b1, previousElementSibling: undefined }; b1 = goog.dom.getPreviousElementSibling(mockB2); assertNotNull('Previous element sibling of mockB2 should not be null', b1); assertEquals('Previous element sibling is b1', 'b1', b1.id); } function testGetChildren() { var p2 = $('p2'); var children = goog.dom.getChildren(p2); assertNotNull('Elements array should not be null', children); assertEquals('List of element children should be length two.', 2, children.length); var b1 = $('b1'); var b2 = $('b2'); assertObjectEquals('First element child should be b1.', b1, children[0]); assertObjectEquals('Second element child should be b2.', b2, children[1]); var noChildren = goog.dom.getChildren(b1); assertNotNull('Element children array should not be null', noChildren); assertEquals('List of element children should be length zero.', 0, noChildren.length); // Test with an undefined children attribute. var mockP2 = { childNodes: [b1, b2], children: undefined }; children = goog.dom.getChildren(mockP2); assertNotNull('Elements array should not be null', children); assertEquals('List of element children should be length two.', 2, children.length); assertObjectEquals('First element child should be b1.', b1, children[0]); assertObjectEquals('Second element child should be b2.', b2, children[1]); } function testGetNextNode() { var tree = goog.dom.htmlToDocumentFragment( '
' + '

Some text

' + '
Some special text
' + '
Foo
' + '
'); assertNull(goog.dom.getNextNode(null)); var node = tree; var next = function() { return node = goog.dom.getNextNode(node); }; assertEquals('P', next().tagName); assertEquals('Some text', next().nodeValue); assertEquals('BLOCKQUOTE', next().tagName); assertEquals('Some ', next().nodeValue); assertEquals('I', next().tagName); assertEquals('special', next().nodeValue); assertEquals(' ', next().nodeValue); assertEquals('B', next().tagName); assertEquals('text', next().nodeValue); assertEquals('ADDRESS', next().tagName); assertEquals(goog.dom.NodeType.COMMENT, next().nodeType); assertEquals('Foo', next().nodeValue); assertNull(next()); } function testGetPreviousNode() { var tree = goog.dom.htmlToDocumentFragment( '
' + '

Some text

' + '
Some special text
' + '
Foo
' + '
'); assertNull(goog.dom.getPreviousNode(null)); var node = tree.lastChild.lastChild; var previous = function() { return node = goog.dom.getPreviousNode(node); }; assertEquals(goog.dom.NodeType.COMMENT, previous().nodeType); assertEquals('ADDRESS', previous().tagName); assertEquals('text', previous().nodeValue); assertEquals('B', previous().tagName); assertEquals(' ', previous().nodeValue); assertEquals('special', previous().nodeValue); assertEquals('I', previous().tagName); assertEquals('Some ', previous().nodeValue); assertEquals('BLOCKQUOTE', previous().tagName); assertEquals('Some text', previous().nodeValue); assertEquals('P', previous().tagName); assertEquals('DIV', previous().tagName); if (!goog.userAgent.IE) { // Internet Explorer maintains a parentNode for Elements after they are // removed from the hierarchy. Everyone else agrees on a null parentNode. assertNull(previous()); } } function testSetTextContent() { var p1 = $('p1'); var s = 'hello world'; goog.dom.setTextContent(p1, s); assertEquals('We should have one childNode after setTextContent', 1, p1.childNodes.length); assertEquals(s, p1.firstChild.data); assertEquals(s, p1.innerHTML); s = 'four elefants < five ants'; var sHtml = 'four elefants < five ants'; goog.dom.setTextContent(p1, s); assertEquals('We should have one childNode after setTextContent', 1, p1.childNodes.length); assertEquals(s, p1.firstChild.data); assertEquals(sHtml, p1.innerHTML); // ensure that we remove existing children p1.innerHTML = 'abc'; s = 'hello world'; goog.dom.setTextContent(p1, s); assertEquals('We should have one childNode after setTextContent', 1, p1.childNodes.length); assertEquals(s, p1.firstChild.data); // same but start with an element p1.innerHTML = 'abc'; s = 'hello world'; goog.dom.setTextContent(p1, s); assertEquals('We should have one childNode after setTextContent', 1, p1.childNodes.length); assertEquals(s, p1.firstChild.data); // clean up p1.innerHTML = ''; } function testFindNode() { var expected = document.body; var result = goog.dom.findNode(document, function(n) { return n.nodeType == goog.dom.NodeType.ELEMENT && n.tagName == 'BODY'; }); assertEquals(expected, result); expected = document.getElementsByTagName('P')[0]; result = goog.dom.findNode(document, function(n) { return n.nodeType == goog.dom.NodeType.ELEMENT && n.tagName == 'P'; }); assertEquals(expected, result); result = goog.dom.findNode(document, function(n) { return false; }); assertUndefined(result); } function testFindNodes() { var expected = document.getElementsByTagName('P'); var result = goog.dom.findNodes(document, function(n) { return n.nodeType == goog.dom.NodeType.ELEMENT && n.tagName == 'P'; }); assertEquals(expected.length, result.length); assertEquals(expected[0], result[0]); assertEquals(expected[1], result[1]); result = goog.dom.findNodes(document, function(n) { return false; }).length; assertEquals(0, result); } function createTestDom(txt) { var dom = goog.dom.createDom('div'); dom.innerHTML = txt; return dom; } function testIsFocusableTabIndex() { assertFalse('isFocusableTabIndex() must be false for no tab index', goog.dom.isFocusableTabIndex(goog.dom.getElement('noTabIndex'))); assertFalse('isFocusableTabIndex() must be false for tab index -2', goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndexNegative2'))); assertFalse('isFocusableTabIndex() must be false for tab index -1', goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndexNegative1'))); // WebKit on Mac doesn't support focusable DIVs until version 526 and later. if (!goog.userAgent.WEBKIT || !goog.userAgent.MAC || goog.userAgent.isVersion('526')) { assertTrue('isFocusableTabIndex() must be true for tab index 0', goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex0'))); assertTrue('isFocusableTabIndex() must be true for tab index 1', goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex1'))); assertTrue('isFocusableTabIndex() must be true for tab index 2', goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex2'))); } } function testSetFocusableTabIndex() { // WebKit on Mac doesn't support focusable DIVs until version 526 and later. if (!goog.userAgent.WEBKIT || !goog.userAgent.MAC || goog.userAgent.isVersion('526')) { // Test enabling focusable tab index. goog.dom.setFocusableTabIndex(goog.dom.getElement('noTabIndex'), true); assertTrue('isFocusableTabIndex() must be true after enabling tab index', goog.dom.isFocusableTabIndex(goog.dom.getElement('noTabIndex'))); // Test disabling focusable tab index that was added programmatically. goog.dom.setFocusableTabIndex(goog.dom.getElement('noTabIndex'), false); assertFalse('isFocusableTabIndex() must be false after disabling tab ' + 'index that was programmatically added', goog.dom.isFocusableTabIndex(goog.dom.getElement('noTabIndex'))); // Test disabling focusable tab index that was specified in markup. goog.dom.setFocusableTabIndex(goog.dom.getElement('tabIndex0'), false); assertFalse('isFocusableTabIndex() must be false after disabling tab ' + 'index that was specified in markup', goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex0'))); // Test re-enabling focusable tab index. goog.dom.setFocusableTabIndex(goog.dom.getElement('tabIndex0'), true); assertTrue('isFocusableTabIndex() must be true after reenabling tabindex', goog.dom.isFocusableTabIndex(goog.dom.getElement('tabIndex0'))); } } function testGetTextContent() { function t(inp, out) { assertEquals(out.replace(/ /g, '_'), goog.dom.getTextContent( createTestDom(inp)).replace(/ /g, '_')); } t('abcde', 'abcde'); t('abcdefgh', 'abcdefgh'); t('a'); assertEquals('SCRIPT', script.tagName); if (goog.userAgent.IE && !goog.userAgent.isDocumentMode(9)) { // Removing an Element from a DOM tree in IE sets its parentNode to a new // DocumentFragment. Bizarre! assertEquals(goog.dom.NodeType.DOCUMENT_FRAGMENT, goog.dom.removeNode(div).parentNode.nodeType); } else { assertNull(div.parentNode); } } function testAppend() { var div = document.createElement('div'); var b = document.createElement('b'); var c = document.createTextNode('c'); goog.dom.append(div, 'a', b, c); assertEqualsCaseAndLeadingWhitespaceInsensitive('ac', div.innerHTML); } function testAppend2() { var div = myIframeDoc.createElement('div'); var b = myIframeDoc.createElement('b'); var c = myIframeDoc.createTextNode('c'); goog.dom.append(div, 'a', b, c); assertEqualsCaseAndLeadingWhitespaceInsensitive('ac', div.innerHTML); } function testAppend3() { var div = document.createElement('div'); var b = document.createElement('b'); var c = document.createTextNode('c'); goog.dom.append(div, ['a', b, c]); assertEqualsCaseAndLeadingWhitespaceInsensitive('ac', div.innerHTML); } function testAppend4() { var div = document.createElement('div'); var div2 = document.createElement('div'); div2.innerHTML = 'ac'; goog.dom.append(div, div2.childNodes); assertEqualsCaseAndLeadingWhitespaceInsensitive('ac', div.innerHTML); assertFalse(div2.hasChildNodes()); } function testGetDocumentScroll() { // setUpPage added divForTestingScrolling to the DOM. It's not init'd here so // it can be shared amonst other tests. window.scrollTo(100, 100); assertEquals(100, goog.dom.getDocumentScroll().x); assertEquals(100, goog.dom.getDocumentScroll().y); } function testGetDocumentScrollOfFixedViewport() { // iOS and perhaps other environments don't actually support scrolling. // Instead, you view the document's fixed layout through a screen viewport. // We need getDocumentScroll to handle this case though. var fakeDocumentScrollElement = {scrollLeft: 0, scrollTop: 0}; var fakeDocument = { defaultView: {pageXOffset: 100, pageYOffset: 100}, documentElement: fakeDocumentScrollElement, body: fakeDocumentScrollElement }; var dh = goog.dom.getDomHelper(document); dh.setDocument(fakeDocument); assertEquals(100, dh.getDocumentScroll().x); assertEquals(100, dh.getDocumentScroll().y); } function testActiveElementIE() { if (!goog.userAgent.IE) { return; } var link = goog.dom.getElement('link'); link.focus(); assertEquals(link.tagName, goog.dom.getActiveElement(document).tagName); assertEquals(link, goog.dom.getActiveElement(document)); } function testParentElement() { var testEl = $('testEl'); var bodyEl = goog.dom.getParentElement(testEl); assertNotNull(bodyEl); var htmlEl = goog.dom.getParentElement(bodyEl); assertNotNull(htmlEl); var documentNotAnElement = goog.dom.getParentElement(htmlEl); assertNull(documentNotAnElement); var tree = goog.dom.htmlToDocumentFragment( '
' + '

Some text

' + '
Some special text
' + '
Foo
' + '
'); assertNull(goog.dom.getParentElement(tree)); pEl = goog.dom.getNextNode(tree); var fragmentRootEl = goog.dom.getParentElement(pEl); assertEquals(tree, fragmentRootEl); var detachedEl = goog.dom.createDom('div'); var detachedHasNoParent = goog.dom.getParentElement(detachedEl); assertNull(detachedHasNoParent); } /** * @return {boolean} Returns true if the userAgent is IE8 or higher. */ function isIE8OrHigher() { return goog.userAgent.IE && goog.userAgent.product.isVersion('8'); }