@apache-royale/royale-js
Version:
Apache Royale (formerly FlexJS)
267 lines (217 loc) • 8.97 kB
JavaScript
// Copyright 2017 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 Tests for {@link goog.html.sanitizer.noclobber} */
goog.module('goog.html.sanitizer.noclobberTest');
goog.setTestOnly();
var NodeType = goog.require('goog.dom.NodeType');
var PropertyReplacer = goog.require('goog.testing.PropertyReplacer');
var noclobber = goog.require('goog.html.sanitizer.noclobber');
var testSuite = goog.require('goog.testing.testSuite');
var testingDom = goog.require('goog.testing.dom');
var userAgentProduct = goog.require('goog.userAgent.product');
/** Whether we support functions that operate on Node and Element. */
const elementAndNodeSupported =
!userAgentProduct.IE || document.documentMode >= 10;
/**
* @param {string} html
* @return {!Element}
*/
function htmlToElement(html) {
var div = document.createElement('div');
div.innerHTML = html;
return div.children[0];
}
/**
* @param {string} name
* @return {!Element}
*/
function createElement(name) {
return htmlToElement('<form id="foo"><input name="' + name + '"></form>');
}
testSuite({
testElement() {
if (!elementAndNodeSupported) {
return;
}
var element = createElement('attributes');
var attributes = noclobber.getElementAttributes(element);
assertEquals('id', attributes[0].name);
element = createElement('hasAttribute');
assertTrue(noclobber.hasElementAttribute(element, 'id'));
assertFalse(noclobber.hasElementAttribute(element, 'bar'));
element = createElement('getAttribute');
assertEquals('foo', noclobber.getElementAttribute(element, 'id'));
element = createElement('setAttribute');
noclobber.setElementAttribute(element, 'id', 'bar');
assertEquals('bar', noclobber.getElementAttribute(element, 'id'));
element = createElement('removeAttribute');
assertTrue(element.hasAttribute('id'));
noclobber.removeElementAttribute(element, 'id');
assertFalse(element.hasAttribute('id'));
element = createElement('innerHTML');
var innerHTML = noclobber.getElementInnerHTML(element);
testingDom.assertHtmlMatches('<input name="innerHTML">', innerHTML);
element = createElement('style');
var style = noclobber.getElementStyle(element);
assertTrue(style instanceof CSSStyleDeclaration);
element = createElement('getElementsByTagName');
assertArrayEquals(
Array.from(element.children),
noclobber.getElementsByTagName(element, 'input'));
element = htmlToElement(
'<form><input name="sheet"><style>color:red</style></form>');
document.body.appendChild(element); // needs to be rooted into the DOM.
assertEquals(
element.children[1].sheet,
noclobber.getElementStyleSheet(element.children[1]));
element = createElement('matches');
assertTrue(noclobber.elementMatches(element, '#foo'));
assertFalse(noclobber.elementMatches(element, '#bar'));
},
testElementClobbered() {
if (!elementAndNodeSupported) {
return;
}
// There's currently no browser in our test suite that throws on clobbering,
// so we delete the saved prototypes to simulate such case.
var replacer = new PropertyReplacer();
var element = createElement('attributes');
replacer.set(noclobber.Methods, 'ATTRIBUTES_GETTER', null);
assertThrows(function() {
noclobber.getElementAttributes(element);
});
element = createElement('hasAttribute');
replacer.set(noclobber.Methods, 'HAS_ATTRIBUTE', null);
assertThrows(function() {
noclobber.hasElementAttribute(element, 'id');
});
element = createElement('getAttribute');
replacer.set(noclobber.Methods, 'GET_ATTRIBUTE', null);
assertThrows(function() {
noclobber.getElementAttribute(element, 'id');
});
element = createElement('setAttribute');
replacer.set(noclobber.Methods, 'SET_ATTRIBUTE', null);
assertThrows(function() {
noclobber.setElementAttribute(element, 'id', 'bar');
});
element = createElement('removeAttribute');
replacer.set(noclobber.Methods, 'REMOVE_ATTRIBUTE', null);
assertThrows(function() {
noclobber.removeElementAttribute(element, 'id');
});
element = createElement('innerHTML');
replacer.set(noclobber.Methods, 'INNER_HTML_GETTER', null);
assertThrows(function() {
noclobber.getElementInnerHTML(element);
});
element = createElement('style');
replacer.set(noclobber.Methods, 'STYLE_GETTER', null);
assertThrows(function() {
noclobber.getElementStyle(element);
});
element = createElement('getElementsByTagName');
replacer.set(noclobber.Methods, 'GET_ELEMENTS_BY_TAG_NAME', null);
assertThrows(function() {
noclobber.getElementsByTagName(element, 'input');
});
// Sheet can't be clobbered, we only test that it works on browsers without
// prototypes.
element = htmlToElement(
'<form><input name="foo"><style>color:red</style></form>');
document.body.appendChild(element); // needs to be rooted into the DOM.
replacer.set(noclobber.Methods, 'SHEET_GETTER', null);
assertEquals(
element.children[1].sheet,
noclobber.getElementStyleSheet(element.children[1]));
element = createElement('matches');
replacer.set(noclobber.Methods, 'MATCHES', null);
assertThrows(function() {
noclobber.elementMatches(element, '#foo');
});
replacer.reset();
},
testNode() {
if (!elementAndNodeSupported) {
return;
}
var element = createElement('nodeName');
assertEquals('FORM', noclobber.getNodeName(element));
element = createElement('nodeType');
noclobber.assertNodeIsElement(element);
assertEquals(NodeType.ELEMENT, noclobber.getNodeType(element));
element = createElement('parentNode');
assertEquals('DIV', noclobber.getParentNode(element).nodeName);
element = createElement('childNodes');
assertTrue(noclobber.getChildNodes(element) instanceof NodeList);
element = createElement('appendChild');
noclobber.appendNodeChild(element, document.createElement('div'));
assertEquals(
'DIV', element.childNodes[element.childNodes.length - 1].nodeName);
},
testNodeClobbered() {
if (!elementAndNodeSupported) {
return;
}
var replacer = new PropertyReplacer();
var element = createElement('nodeName');
replacer.set(noclobber.Methods, 'NODE_NAME_GETTER', null);
assertThrows(function() {
noclobber.getNodeName(element);
});
element = createElement('nodeType');
replacer.set(noclobber.Methods, 'NODE_TYPE_GETTER', null);
assertThrows(function() {
noclobber.getNodeType(element);
});
element = createElement('parentNode');
replacer.set(noclobber.Methods, 'PARENT_NODE_GETTER', null);
assertThrows(function() {
noclobber.getParentNode(element);
});
element = createElement('childNodes');
replacer.set(noclobber.Methods, 'CHILD_NODES_GETTER', null);
assertThrows(function() {
noclobber.getChildNodes(element);
});
element = createElement('appendChild');
replacer.set(noclobber.Methods, 'APPEND_CHILD', null);
assertThrows(function() {
noclobber.appendNodeChild(element, document.createElement('div'));
});
replacer.reset();
},
testCSSStyleDeclaration() {
// Properties on the CSSStyleDeclaration object can't be clobbered.
var element =
htmlToElement('<form style="color:red"><input name="test"></form>');
assertEquals('red', noclobber.getCssPropertyValue(element.style, 'color'));
noclobber.setCssProperty(element.style, 'color', 'black');
assertEquals('black', element.style.color);
},
testCSSStyleDeclarationOldBrowser() {
// Properties on the CSSStyleDeclaration object can't be clobbered, we only
// test that they work on browsers without prototypes.
var replacer = new PropertyReplacer();
replacer.set(noclobber.Methods, 'GET_PROPERTY_VALUE', null);
var element = htmlToElement(
'<form style="color:red"><input name="' +
(userAgentProduct.IE ? 'getAttribute' : 'getPropertyValue') +
'" style="color: green"></form>');
assertEquals('red', noclobber.getCssPropertyValue(element.style, 'color'));
noclobber.setCssProperty(element.style, 'color', 'black');
assertEquals('black', element.style.color);
replacer.reset();
}
});