diff options
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/testing/dom.js')
-rw-r--r-- | contexts/data/lib/closure-library/closure/goog/testing/dom.js | 606 |
1 files changed, 0 insertions, 606 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/testing/dom.js b/contexts/data/lib/closure-library/closure/goog/testing/dom.js deleted file mode 100644 index 1179a29..0000000 --- a/contexts/data/lib/closure-library/closure/goog/testing/dom.js +++ /dev/null @@ -1,606 +0,0 @@ -// 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. - -/** - * @fileoverview Testing utilities for DOM related tests. - * - * @author robbyw@google.com (Robby Walker) - */ - -goog.provide('goog.testing.dom'); - -goog.require('goog.dom'); -goog.require('goog.dom.NodeIterator'); -goog.require('goog.dom.NodeType'); -goog.require('goog.dom.TagIterator'); -goog.require('goog.dom.TagName'); -goog.require('goog.dom.classes'); -goog.require('goog.iter'); -goog.require('goog.object'); -goog.require('goog.string'); -goog.require('goog.style'); -goog.require('goog.testing.asserts'); -goog.require('goog.userAgent'); - - -/** - * A unique object to use as an end tag marker. - * @type {Object} - * @private - */ -goog.testing.dom.END_TAG_MARKER_ = {}; - - -/** - * Tests if the given iterator over nodes matches the given Array of node - * descriptors. Throws an error if any match fails. - * @param {goog.iter.Iterator} it An iterator over nodes. - * @param {Array.<Node|number|string>} array Array of node descriptors to match - * against. Node descriptors can be any of the following: - * Node: Test if the two nodes are equal. - * number: Test node.nodeType == number. - * string starting with '#': Match the node's id with the text - * after "#". - * other string: Match the text node's contents. - */ -goog.testing.dom.assertNodesMatch = function(it, array) { - var i = 0; - goog.iter.forEach(it, function(node) { - if (array.length <= i) { - fail('Got more nodes than expected: ' + goog.testing.dom.describeNode_( - node)); - } - var expected = array[i]; - - if (goog.dom.isNodeLike(expected)) { - assertEquals('Nodes should match at position ' + i, expected, node); - } else if (goog.isNumber(expected)) { - assertEquals('Node types should match at position ' + i, expected, - node.nodeType); - } else if (expected.charAt(0) == '#') { - assertEquals('Expected element at position ' + i, - goog.dom.NodeType.ELEMENT, node.nodeType); - var expectedId = expected.substr(1); - assertEquals('IDs should match at position ' + i, - expectedId, node.id); - - } else { - assertEquals('Expected text node at position ' + i, - goog.dom.NodeType.TEXT, node.nodeType); - assertEquals('Node contents should match at position ' + i, - expected, node.nodeValue); - } - - i++; - }); - - assertEquals('Used entire match array', array.length, i); -}; - - -/** - * Exposes a node as a string. - * @param {Node} node A node. - * @return {string} A string representation of the node. - */ -goog.testing.dom.exposeNode = function(node) { - return (node.tagName || node.nodeValue) + (node.id ? '#' + node.id : '') + - ':"' + (node.innerHTML || '') + '"'; -}; - - -/** - * Exposes the nodes of a range wrapper as a string. - * @param {goog.dom.AbstractRange} range A range. - * @return {string} A string representation of the range. - */ -goog.testing.dom.exposeRange = function(range) { - // This is deliberately not implemented as - // goog.dom.AbstractRange.prototype.toString, because it is non-authoritative. - // Two equivalent ranges may have very different exposeRange values, and - // two different ranges may have equal exposeRange values. - // (The mapping of ranges to DOM nodes/offsets is a many-to-many mapping). - if (!range) { - return 'null'; - } - return goog.testing.dom.exposeNode(range.getStartNode()) + ':' + - range.getStartOffset() + ' to ' + - goog.testing.dom.exposeNode(range.getEndNode()) + ':' + - range.getEndOffset(); -}; - - -/** - * Determines if the current user agent matches the specified string. Returns - * false if the string does specify at least one user agent but does not match - * the running agent. - * @param {string} userAgents Space delimited string of user agents. - * @return {boolean} Whether the user agent was matched. Also true if no user - * agent was listed in the expectation string. - * @private - */ -goog.testing.dom.checkUserAgents_ = function(userAgents) { - if (goog.string.startsWith(userAgents, '!')) { - if (goog.string.contains(userAgents, ' ')) { - throw new Error('Only a single negative user agent may be specified'); - } - return !goog.userAgent[userAgents.substr(1)]; - } - - var agents = userAgents.split(' '); - var hasUserAgent = false; - for (var i = 0, len = agents.length; i < len; i++) { - var cls = agents[i]; - if (cls in goog.userAgent) { - hasUserAgent = true; - if (goog.userAgent[cls]) { - return true; - } - } - } - // If we got here, there was a user agent listed but we didn't match it. - return !hasUserAgent; -}; - - -/** - * Map function that converts end tags to a specific object. - * @param {Node} node The node to map. - * @param {Object} ignore Always undefined. - * @param {goog.dom.TagIterator} iterator The iterator. - * @return {Node|Object} The resulting iteration item. - * @private - */ -goog.testing.dom.endTagMap_ = function(node, ignore, iterator) { - return iterator.isEndTag() ? goog.testing.dom.END_TAG_MARKER_ : node; -}; - - -/** - * Check if the given node is important. A node is important if it is a - * non-empty text node, a non-annotated element, or an element annotated to - * match on this user agent. - * @param {Node} node The node to test. - * @return {boolean} Whether this node should be included for iteration. - * @private - */ -goog.testing.dom.nodeFilter_ = function(node) { - if (node.nodeType == goog.dom.NodeType.TEXT) { - // If a node is part of a string of text nodes and it has spaces in it, - // we allow it since it's going to affect the merging of nodes done below. - if (goog.string.isBreakingWhitespace(node.nodeValue) && - (!node.previousSibling || - node.previousSibling.nodeType != goog.dom.NodeType.TEXT) && - (!node.nextSibling || - node.nextSibling.nodeType != goog.dom.NodeType.TEXT)) { - return false; - } - // Allow optional text to be specified as [[BROWSER1 BROWSER2]]Text - var match = node.nodeValue.match(/^\[\[(.+)\]\]/); - if (match) { - return goog.testing.dom.checkUserAgents_(match[1]); - } - } else if (node.className) { - return goog.testing.dom.checkUserAgents_(node.className); - } - return true; -}; - - -/** - * Determines the text to match from the given node, removing browser - * specification strings. - * @param {Node} node The node expected to match. - * @return {string} The text, stripped of browser specification strings. - * @private - */ -goog.testing.dom.getExpectedText_ = function(node) { - // Strip off the browser specifications. - return node.nodeValue.match(/^(\[\[.+\]\])?(.*)/)[2]; -}; - - -/** - * Describes the given node. - * @param {Node} node The node to describe. - * @return {string} A description of the node. - * @private - */ -goog.testing.dom.describeNode_ = function(node) { - if (node.nodeType == goog.dom.NodeType.TEXT) { - return '[Text: ' + node.nodeValue + ']'; - } else { - return '<' + node.tagName + (node.id ? ' #' + node.id : '') + ' .../>'; - } -}; - - -/** - * Assert that the html in {@code actual} is substantially similar to - * htmlPattern. This method tests for the same set of styles, for the same - * order of nodes, and the presence of attributes. Breaking whitespace nodes - * are ignored. Elements can be - * annotated with classnames corresponding to keys in goog.userAgent and will be - * expected to show up in that user agent and expected not to show up in - * others. - * @param {string} htmlPattern The pattern to match. - * @param {!Element} actual The element to check: its contents are matched - * against the HTML pattern. - * @param {boolean=} opt_strictAttributes If false, attributes that appear in - * htmlPattern must be in actual, but actual can have attributes not - * present in htmlPattern. If true, htmlPattern and actual must have the - * same set of attributes. Default is false. - */ -goog.testing.dom.assertHtmlContentsMatch = function(htmlPattern, actual, - opt_strictAttributes) { - var div = goog.dom.createDom(goog.dom.TagName.DIV); - div.innerHTML = htmlPattern; - - var errorSuffix = '\nExpected\n' + htmlPattern + '\nActual\n' + - actual.innerHTML; - - var actualIt = goog.iter.filter( - goog.iter.map(new goog.dom.TagIterator(actual), - goog.testing.dom.endTagMap_), - goog.testing.dom.nodeFilter_); - - var expectedIt = goog.iter.filter(new goog.dom.NodeIterator(div), - goog.testing.dom.nodeFilter_); - - var actualNode; - var preIterated = false; - var advanceActualNode = function() { - // If the iterator has already been advanced, don't advance it again. - if (!preIterated) { - actualNode = /** @type {Node} */ (goog.iter.nextOrValue(actualIt, null)); - } - preIterated = false; - - // Advance the iterator so long as it is return end tags. - while (actualNode == goog.testing.dom.END_TAG_MARKER_) { - actualNode = /** @type {Node} */ (goog.iter.nextOrValue(actualIt, null)); - } - }; - - // HACK(brenneman): IE has unique ideas about whitespace handling when setting - // innerHTML. This results in elision of leading whitespace in the expected - // nodes where doing so doesn't affect visible rendering. As a workaround, we - // remove the leading whitespace in the actual nodes where necessary. - // - // The collapsible variable tracks whether we should collapse the whitespace - // in the next Text node we encounter. - var IE_TEXT_COLLAPSE = goog.userAgent.IE && !goog.userAgent.isVersion('9'); - var collapsible = true; - - var number = 0; - goog.iter.forEach(expectedIt, function(expectedNode) { - expectedNode = /** @type {Node} */ (expectedNode); - - advanceActualNode(); - assertNotNull('Finished actual HTML before finishing expected HTML at ' + - 'node number ' + number + ': ' + - goog.testing.dom.describeNode_(expectedNode) + errorSuffix, - actualNode); - - // Do no processing for expectedNode == div. - if (expectedNode == div) { - return; - } - - assertEquals('Should have the same node type, got ' + - goog.testing.dom.describeNode_(actualNode) + ' but expected ' + - goog.testing.dom.describeNode_(expectedNode) + '.' + errorSuffix, - expectedNode.nodeType, actualNode.nodeType); - - if (expectedNode.nodeType == goog.dom.NodeType.ELEMENT) { - assertEquals('Tag names should match' + errorSuffix, - expectedNode.tagName, actualNode.tagName); - assertObjectEquals('Should have same styles' + errorSuffix, - goog.style.parseStyleAttribute(expectedNode.style.cssText), - goog.style.parseStyleAttribute(actualNode.style.cssText)); - goog.testing.dom.assertAttributesEqual_(errorSuffix, expectedNode, - actualNode, !!opt_strictAttributes); - - if (IE_TEXT_COLLAPSE && - goog.style.getCascadedStyle( - /** @type {Element} */ (actualNode), 'display') != 'inline') { - // Text may be collapsed after any non-inline element. - collapsible = true; - } - } else { - // Concatenate text nodes until we reach a non text node. - var actualText = actualNode.nodeValue; - preIterated = true; - while ((actualNode = /** @type {Node} */ - (goog.iter.nextOrValue(actualIt, null))) && - actualNode.nodeType == goog.dom.NodeType.TEXT) { - actualText += actualNode.nodeValue; - } - - if (IE_TEXT_COLLAPSE) { - // Collapse the leading whitespace, unless the string consists entirely - // of whitespace. - if (collapsible && !goog.string.isEmpty(actualText)) { - actualText = goog.string.trimLeft(actualText); - } - // Prepare to collapse whitespace in the next Text node if this one does - // not end in a whitespace character. - collapsible = /\s$/.test(actualText); - } - - var expectedText = goog.testing.dom.getExpectedText_(expectedNode); - if ((actualText && !goog.string.isBreakingWhitespace(actualText)) || - (expectedText && !goog.string.isBreakingWhitespace(expectedText))) { - var normalizedActual = actualText.replace(/\s+/g, ' '); - var normalizedExpected = expectedText.replace(/\s+/g, ' '); - - assertEquals('Text should match' + errorSuffix, normalizedExpected, - normalizedActual); - } - } - - number++; - }); - - advanceActualNode(); - assertNull('Finished expected HTML before finishing actual HTML' + - errorSuffix, goog.iter.nextOrValue(actualIt, null)); -}; - - -/** - * Assert that the html in {@code actual} is substantially similar to - * htmlPattern. This method tests for the same set of styles, and for the same - * order of nodes. Breaking whitespace nodes are ignored. Elements can be - * annotated with classnames corresponding to keys in goog.userAgent and will be - * expected to show up in that user agent and expected not to show up in - * others. - * @param {string} htmlPattern The pattern to match. - * @param {string} actual The html to check. - */ -goog.testing.dom.assertHtmlMatches = function(htmlPattern, actual) { - var div = goog.dom.createDom(goog.dom.TagName.DIV); - div.innerHTML = actual; - - goog.testing.dom.assertHtmlContentsMatch(htmlPattern, div); -}; - - -/** - * Finds the first text node descendant of root with the given content. Note - * that this operates on a text node level, so if text nodes get split this - * may not match the user visible text. Using normalize() may help here. - * @param {string|RegExp} textOrRegexp The text to find, or a regular - * expression to find a match of. - * @param {Element} root The element to search in. - * @return {Node} The first text node that matches, or null if none is found. - */ -goog.testing.dom.findTextNode = function(textOrRegexp, root) { - var it = new goog.dom.NodeIterator(root); - var ret = goog.iter.nextOrValue(goog.iter.filter(it, function(node) { - if (node.nodeType == goog.dom.NodeType.TEXT) { - if (goog.isString(textOrRegexp)) { - return node.nodeValue == textOrRegexp; - } else { - return !!node.nodeValue.match(textOrRegexp); - } - } else { - return false; - } - }), null); - return /** @type {Node} */ (ret); -}; - - -/** - * Assert the end points of a range. - * - * Notice that "Are two ranges visually identical?" and "Do two ranges have - * the same endpoint?" are independent questions. Two visually identical ranges - * may have different endpoints. And two ranges with the same endpoints may - * be visually different. - * - * @param {Node} start The expected start node. - * @param {number} startOffset The expected start offset. - * @param {Node} end The expected end node. - * @param {number} endOffset The expected end offset. - * @param {goog.dom.AbstractRange} range The actual range. - */ -goog.testing.dom.assertRangeEquals = function(start, startOffset, end, - endOffset, range) { - assertEquals('Unexpected start node', start, range.getStartNode()); - assertEquals('Unexpected end node', end, range.getEndNode()); - assertEquals('Unexpected start offset', startOffset, range.getStartOffset()); - assertEquals('Unexpected end offset', endOffset, range.getEndOffset()); -}; - - -/** - * Gets the value of a DOM attribute in deterministic way. - * @param {!Node} node A node. - * @param {string} name Attribute name. - * @return {*} Attribute value. - * @private - */ -goog.testing.dom.getAttributeValue_ = function(node, name) { - // These hacks avoid nondetermistic results in the following cases: - // IE7: document.createElement('input').height returns a random number. - // FF3: getAttribute('disabled') returns different value for <div disabled=""> - // and <div disabled="disabled"> - // WebKit: Two radio buttons with the same name can't be checked at the same - // time, even if only one of them is in the document. - if (goog.userAgent.WEBKIT && node.tagName == 'INPUT' && - node['type'] == 'radio' && name == 'checked') { - return false; - } - return goog.isDef(node[name]) && - typeof node.getAttribute(name) != typeof node[name] ? - node[name] : node.getAttribute(name); -}; - - -/** - * Assert that the attributes of two Nodes are the same (ignoring any - * instances of the style attribute). - * @param {string} errorSuffix String to add to end of error messages. - * @param {Node} expectedNode The node whose attributes we are expecting. - * @param {Node} actualNode The node with the actual attributes. - * @param {boolean} strictAttributes If false, attributes that appear in - * expectedNode must also be in actualNode, but actualNode can have - * attributes not present in expectedNode. If true, expectedNode and - * actualNode must have the same set of attributes. - * @private - */ -goog.testing.dom.assertAttributesEqual_ = function(errorSuffix, - expectedNode, actualNode, strictAttributes) { - if (strictAttributes) { - goog.testing.dom.compareClassAttribute_(expectedNode, actualNode); - } - - var expectedAttributes = expectedNode.attributes; - var actualAttributes = actualNode.attributes; - - for (var i = 0, len = expectedAttributes.length; i < len; i++) { - var expectedName = expectedAttributes[i].name; - var expectedValue = goog.testing.dom.getAttributeValue_(expectedNode, - expectedName); - - var actualAttribute = actualAttributes[expectedName]; - var actualValue = goog.testing.dom.getAttributeValue_(actualNode, - expectedName); - - // IE enumerates attribute names in the expected node that are not present, - // causing an undefined actualAttribute. - if (!expectedValue && !actualValue) { - continue; - } - - if (expectedName == 'id' && goog.userAgent.IE) { - goog.testing.dom.compareIdAttributeForIe_( - /** @type {string} */ (expectedValue), actualAttribute, - strictAttributes, errorSuffix); - continue; - } - - if (goog.testing.dom.ignoreAttribute_(expectedName)) { - continue; - } - - assertNotUndefined('Expected to find attribute with name ' + - expectedName + ', in element ' + - goog.testing.dom.describeNode_(actualNode) + errorSuffix, - actualAttribute); - assertEquals('Expected attribute ' + expectedName + - ' has a different value ' + errorSuffix, - expectedValue, - goog.testing.dom.getAttributeValue_(actualNode, actualAttribute.name)); - } - - if (strictAttributes) { - for (i = 0; i < actualAttributes.length; i++) { - var actualName = actualAttributes[i].name; - var actualAttribute = actualAttributes.getNamedItem(actualName); - - if (!actualAttribute || goog.testing.dom.ignoreAttribute_(actualName)) { - continue; - } - - assertNotUndefined('Unexpected attribute with name ' + - actualName + ' in element ' + - goog.testing.dom.describeNode_(actualNode) + errorSuffix, - expectedAttributes[actualName]); - } - } -}; - - -/** - * Assert the class attribute of actualNode is the same as the one in - * expectedNode, ignoring classes that are useragents. - * @param {Node} expectedNode The DOM node whose class we expect. - * @param {Node} actualNode The DOM node with the actual class. - * @private - */ -goog.testing.dom.compareClassAttribute_ = function(expectedNode, - actualNode) { - var classes = goog.dom.classes.get(expectedNode); - - var expectedClasses = []; - for (var i = 0, len = classes.length; i < len; i++) { - if (!(classes[i] in goog.userAgent)) { - expectedClasses.push(classes[i]); - } - } - expectedClasses.sort(); - - var actualClasses = goog.dom.classes.get(actualNode); - actualClasses.sort(); - - assertArrayEquals( - 'Expected class was: ' + expectedClasses.join(' ') + - ', but actual class was: ' + actualNode.className, - expectedClasses, actualClasses); -}; - - -/** - * Set of attributes IE adds to elements randomly. - * @type {Object} - * @private - */ -goog.testing.dom.BAD_IE_ATTRIBUTES_ = goog.object.createSet( - 'methods', 'CHECKED', 'dataFld', 'dataFormatAs', 'dataSrc'); - - -/** - * Whether to ignore the attribute. - * @param {string} name Name of the attribute. - * @return {boolean} True if the attribute should be ignored. - * @private - */ -goog.testing.dom.ignoreAttribute_ = function(name) { - if (name == 'style' || name == 'class') { - return true; - } - return goog.userAgent.IE && goog.testing.dom.BAD_IE_ATTRIBUTES_[name]; -}; - - -/** - * Compare id attributes for IE. In IE, if an element lacks an id attribute - * in the original HTML, the element object will still have such an attribute, - * but its value will be the empty string. - * @param {string} expectedValue The expected value of the id attribute. - * @param {Attr} actualAttribute The actual id attribute. - * @param {boolean} strictAttributes Whether strict attribute checking should be - * done. - * @param {string} errorSuffix String to append to error messages. - * @private - */ -goog.testing.dom.compareIdAttributeForIe_ = function(expectedValue, - actualAttribute, strictAttributes, errorSuffix) { - if (expectedValue === '') { - if (strictAttributes) { - assertTrue('Unexpected attribute with name id in element ' + - errorSuffix, actualAttribute.value == ''); - } - } else { - assertNotUndefined('Expected to find attribute with name id, in element ' + - errorSuffix, actualAttribute); - assertNotEquals('Expected to find attribute with name id, in element ' + - errorSuffix, '', actualAttribute.value); - assertEquals('Expected attribute has a different value ' + errorSuffix, - expectedValue, actualAttribute.value); - } -}; |