blob: 80b5002ff1cfbf50ad82d32fc465426f21e47038 [file] [log] [blame]
// 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.cssomTest');
goog.setTestOnly('goog.cssomTest');
goog.require('goog.array');
goog.require('goog.cssom');
goog.require('goog.cssom.CssRuleType');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
// Since sheet cssom_test1.css's first line is to import
// cssom_test2.css, we should get 2 before one in the string.
var cssText = '.css-link-1 { display: block; } ' +
'.css-import-2 { display: block; } ' +
'.css-import-1 { display: block; } ' +
'.css-style-1 { display: block; } ' +
'.css-style-2 { display: block; } ' +
'.css-style-3 { display: block; }';
var replacementCssText = '.css-repl-1 { display: block; }';
var isIe7 = goog.userAgent.IE &&
(goog.userAgent.compare(goog.userAgent.VERSION, '7.0') == 0);
// We're going to toLowerCase cssText before testing, because IE returns
// CSS property names in UPPERCASE, and the function shouldn't
// "fix" the text as it would be expensive and rarely of use.
// Same goes for the trailing whitespace in IE.
// Same goes for fixing the optimized removal of trailing ; in rules.
// Also needed for Opera.
function fixCssTextForIe(cssText) {
cssText = cssText.toLowerCase().replace(/\s*$/, '');
if (cssText.match(/[^;] \}/)) {
cssText = cssText.replace(/([^;]) \}/g, '$1; }');
}
return cssText;
}
function testGetFileNameFromStyleSheet() {
var styleSheet = {'href': 'http://foo.com/something/filename.css'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
styleSheet = {'href': 'https://foo.com:123/something/filename.css'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
styleSheet = {'href': 'http://foo.com/something/filename.css?bar=bas'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
styleSheet = {'href': 'filename.css?bar=bas'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
styleSheet = {'href': 'filename.css'};
assertEquals('filename.css',
goog.cssom.getFileNameFromStyleSheet(styleSheet));
}
function testGetAllCssStyleSheets() {
var styleSheets = goog.cssom.getAllCssStyleSheets();
assertEquals(4, styleSheets.length);
// Makes sure they're in the right cascade order.
assertEquals('cssom_test_link_1.css',
goog.cssom.getFileNameFromStyleSheet(styleSheets[0]));
assertEquals('cssom_test_import_2.css',
goog.cssom.getFileNameFromStyleSheet(styleSheets[1]));
assertEquals('cssom_test_import_1.css',
goog.cssom.getFileNameFromStyleSheet(styleSheets[2]));
// Not an external styleSheet
assertNull(goog.cssom.getFileNameFromStyleSheet(styleSheets[3]));
}
function testGetAllCssText() {
var allCssText = goog.cssom.getAllCssText();
// In IE7, a CSSRule object gets included twice and replaces another
// existing CSSRule object. We aren't using
// goog.testing.ExpectedFailures since it brings in additional CSS
// which breaks a lot of our expectations about the number of rules
// present in a style sheet.
if (!isIe7) {
assertEquals(cssText, fixCssTextForIe(allCssText));
}
}
function testGetAllCssStyleRules() {
var allCssRules = goog.cssom.getAllCssStyleRules();
assertEquals(6, allCssRules.length);
}
function testAddCssText() {
var newCssText = '.css-add-1 { display: block; }';
var newCssNode = goog.cssom.addCssText(newCssText);
assertEquals(document.styleSheets.length, 3);
var allCssText = goog.cssom.getAllCssText();
// In IE7, a CSSRule object gets included twice and replaces another
// existing CSSRule object. We aren't using
// goog.testing.ExpectedFailures since it brings in additional CSS
// which breaks a lot of our expectations about the number of rules
// present in a style sheet.
if (!isIe7) {
// Opera inserts the CSSRule to the first position. And fixCssText
// is also needed to clean up whitespace.
if (goog.userAgent.OPERA) {
assertEquals(newCssText + ' ' + cssText,
fixCssTextForIe(allCssText));
} else {
assertEquals(cssText + ' ' + newCssText,
fixCssTextForIe(allCssText));
}
}
var cssRules = goog.cssom.getAllCssStyleRules();
assertEquals(7, cssRules.length);
// Remove the new stylesheet now so it doesn't interfere with other
// tests.
newCssNode.parentNode.removeChild(newCssNode);
// Sanity check.
cssRules = goog.cssom.getAllCssStyleRules();
assertEquals(6, cssRules.length);
}
function testAddCssRule() {
// test that addCssRule correctly adds the rule to the style
// sheet.
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var newCssRule = '.css-addCssRule { display: block; }';
var rules = styleSheet.rules || styleSheet.cssRules;
var origNumberOfRules = rules.length;
goog.cssom.addCssRule(styleSheet, newCssRule, 1);
rules = styleSheet.rules || styleSheet.cssRules;
var newNumberOfRules = rules.length;
assertEquals(newNumberOfRules, origNumberOfRules + 1);
// Remove the added rule so we don't mess up other tests.
goog.cssom.removeCssRule(styleSheet, 1);
}
function testAddCssRuleAtPos() {
// test that addCssRule correctly adds the rule to the style
// sheet at the specified position.
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var newCssRule = '.css-addCssRulePos { display: block; }';
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var origNumberOfRules = rules.length;
// Firefox croaks if we try to insert a CSSRule at an index that
// contains a CSSImport Rule. Since we deal only with CSSStyleRule
// objects, we find the first CSSStyleRule and return its index.
//
// NOTE(user): We could have unified the code block below for all
// browsers but IE6 horribly mangled up the stylesheet by creating
// duplicate instances of a rule when removeCssRule was invoked
// just after addCssRule with the looping construct in. This is
// perfectly fine since IE's styleSheet.rules does not contain
// references to anything but CSSStyleRules.
var pos = 0;
if (styleSheet.cssRules) {
pos = goog.array.findIndex(rules, function(rule) {
return rule.type == goog.cssom.CssRuleType.STYLE;
});
}
goog.cssom.addCssRule(styleSheet, newCssRule, pos);
rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var newNumberOfRules = rules.length;
assertEquals(newNumberOfRules, origNumberOfRules + 1);
// Remove the added rule so we don't mess up other tests.
goog.cssom.removeCssRule(styleSheet, pos);
rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
assertEquals(origNumberOfRules, rules.length);
}
function testAddCssRuleNoIndex() {
// How well do we handle cases where the optional index is
// not passed in?
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var origNumberOfRules = rules.length;
var newCssRule = '.css-addCssRuleNoIndex { display: block; }';
// Try inserting the rule without specifying an index.
// Make sure we don't throw an exception, and that we added
// the entry.
goog.cssom.addCssRule(styleSheet, newCssRule);
rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var newNumberOfRules = rules.length;
assertEquals(newNumberOfRules, origNumberOfRules + 1);
// Remove the added rule so we don't mess up the other tests.
goog.cssom.removeCssRule(styleSheet, newNumberOfRules - 1);
rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
assertEquals(origNumberOfRules, rules.length);
}
function testGetParentStyleSheetAfterGetAllCssStyleRules() {
var cssRules = goog.cssom.getAllCssStyleRules();
var cssRule = cssRules[4];
var parentStyleSheet = goog.cssom.getParentStyleSheet(cssRule);
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
assertEquals(styleSheet, parentStyleSheet);
}
function testGetCssRuleIndexInParentStyleSheetAfterGetAllCssStyleRules() {
var cssRules = goog.cssom.getAllCssStyleRules();
var cssRule = cssRules[4];
// Note here that this is correct - IE's styleSheet.rules does not
// contain references to anything but CSSStyleRules while FF and others
// include anything that inherits from the CSSRule interface.
// See http://dev.w3.org/csswg/cssom/#cssrule.
var parentStyleSheet = goog.cssom.getParentStyleSheet(cssRule);
var ruleIndex = goog.isDefAndNotNull(parentStyleSheet.cssRules) ? 2 : 1;
assertEquals(ruleIndex,
goog.cssom.getCssRuleIndexInParentStyleSheet(cssRule));
}
function testGetCssRuleIndexInParentStyleSheetNonStyleRule() {
// IE's styleSheet.rules only contain CSSStyleRules.
if (!goog.userAgent.IE) {
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var newCssRule = '@media print { .css-nonStyle { display: block; } }';
goog.cssom.addCssRule(styleSheet, newCssRule);
var rules = styleSheet.rules || styleSheet.cssRules;
var cssRule = rules[rules.length - 1];
assertEquals(goog.cssom.CssRuleType.MEDIA, cssRule.type);
// Make sure we don't throw an exception.
goog.cssom.getCssRuleIndexInParentStyleSheet(cssRule, styleSheet);
// Remove the added rule.
goog.cssom.removeCssRule(styleSheet, rules.length - 1);
}
}
// Tests the scenario where we have a known stylesheet and index.
function testReplaceCssRuleWithStyleSheetAndIndex() {
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var index = 2;
var origCssRule = rules[index];
var origCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(origCssRule));
goog.cssom.replaceCssRule(origCssRule, replacementCssText, styleSheet,
index);
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var newCssRule = rules[index];
var newCssText = goog.cssom.getCssTextFromCssRule(newCssRule);
assertEquals(replacementCssText, fixCssTextForIe(newCssText));
// Now we need to re-replace our rule, to preserve parity for the other
// tests.
goog.cssom.replaceCssRule(newCssRule, origCssText, styleSheet, index);
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var nowCssRule = rules[index];
var nowCssText = goog.cssom.getCssTextFromCssRule(nowCssRule);
assertEquals(origCssText, fixCssTextForIe(nowCssText));
}
function testReplaceCssRuleUsingGetAllCssStyleRules() {
var cssRules = goog.cssom.getAllCssStyleRules();
var origCssRule = cssRules[4];
var origCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(origCssRule));
// notice we don't pass in the stylesheet or index.
goog.cssom.replaceCssRule(origCssRule, replacementCssText);
var styleSheets = goog.cssom.getAllCssStyleSheets();
var styleSheet = styleSheets[3];
var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
var index = goog.isDefAndNotNull(styleSheet.cssRules) ? 2 : 1;
var newCssRule = rules[index];
var newCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(newCssRule));
assertEquals(replacementCssText, newCssText);
// try getting it the other way around too.
var cssRules = goog.cssom.getAllCssStyleRules();
var newCssRule = cssRules[4];
var newCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(newCssRule));
assertEquals(replacementCssText, newCssText);
// Now we need to re-replace our rule, to preserve parity for the other
// tests.
goog.cssom.replaceCssRule(newCssRule, origCssText);
var cssRules = goog.cssom.getAllCssStyleRules();
var nowCssRule = cssRules[4];
var nowCssText =
fixCssTextForIe(goog.cssom.getCssTextFromCssRule(nowCssRule));
assertEquals(origCssText, nowCssText);
}