cssom_test.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.cssomTest');
  15. goog.setTestOnly('goog.cssomTest');
  16. goog.require('goog.array');
  17. goog.require('goog.cssom');
  18. goog.require('goog.cssom.CssRuleType');
  19. goog.require('goog.testing.jsunit');
  20. goog.require('goog.userAgent');
  21. // Since sheet cssom_test1.css's first line is to import
  22. // cssom_test2.css, we should get 2 before one in the string.
  23. var cssText = '.css-link-1 { display: block; } ' +
  24. '.css-import-2 { display: block; } ' +
  25. '.css-import-1 { display: block; } ' +
  26. '.css-style-1 { display: block; } ' +
  27. '.css-style-2 { display: block; } ' +
  28. '.css-style-3 { display: block; }';
  29. var replacementCssText = '.css-repl-1 { display: block; }';
  30. var isIe7 = goog.userAgent.IE &&
  31. (goog.userAgent.compare(goog.userAgent.VERSION, '7.0') == 0);
  32. // We're going to toLowerCase cssText before testing, because IE returns
  33. // CSS property names in UPPERCASE, and the function shouldn't
  34. // "fix" the text as it would be expensive and rarely of use.
  35. // Same goes for the trailing whitespace in IE.
  36. // Same goes for fixing the optimized removal of trailing ; in rules.
  37. // Also needed for Opera.
  38. function fixCssTextForIe(cssText) {
  39. cssText = cssText.toLowerCase().replace(/\s*$/, '');
  40. if (cssText.match(/[^;] \}/)) {
  41. cssText = cssText.replace(/([^;]) \}/g, '$1; }');
  42. }
  43. return cssText;
  44. }
  45. function testGetFileNameFromStyleSheet() {
  46. var styleSheet = {'href': 'http://foo.com/something/filename.css'};
  47. assertEquals(
  48. 'filename.css', goog.cssom.getFileNameFromStyleSheet(styleSheet));
  49. styleSheet = {'href': 'https://foo.com:123/something/filename.css'};
  50. assertEquals(
  51. 'filename.css', goog.cssom.getFileNameFromStyleSheet(styleSheet));
  52. styleSheet = {'href': 'http://foo.com/something/filename.css?bar=bas'};
  53. assertEquals(
  54. 'filename.css', goog.cssom.getFileNameFromStyleSheet(styleSheet));
  55. styleSheet = {'href': 'filename.css?bar=bas'};
  56. assertEquals(
  57. 'filename.css', goog.cssom.getFileNameFromStyleSheet(styleSheet));
  58. styleSheet = {'href': 'filename.css'};
  59. assertEquals(
  60. 'filename.css', goog.cssom.getFileNameFromStyleSheet(styleSheet));
  61. }
  62. function testGetAllCssStyleSheets() {
  63. var styleSheets = goog.cssom.getAllCssStyleSheets();
  64. assertEquals(4, styleSheets.length);
  65. // Makes sure they're in the right cascade order.
  66. assertEquals(
  67. 'cssom_test_link_1.css',
  68. goog.cssom.getFileNameFromStyleSheet(styleSheets[0]));
  69. assertEquals(
  70. 'cssom_test_import_2.css',
  71. goog.cssom.getFileNameFromStyleSheet(styleSheets[1]));
  72. assertEquals(
  73. 'cssom_test_import_1.css',
  74. goog.cssom.getFileNameFromStyleSheet(styleSheets[2]));
  75. // Not an external styleSheet
  76. assertNull(goog.cssom.getFileNameFromStyleSheet(styleSheets[3]));
  77. }
  78. function testGetAllCssText() {
  79. var allCssText = goog.cssom.getAllCssText();
  80. // In IE7, a CSSRule object gets included twice and replaces another
  81. // existing CSSRule object. We aren't using
  82. // goog.testing.ExpectedFailures since it brings in additional CSS
  83. // which breaks a lot of our expectations about the number of rules
  84. // present in a style sheet.
  85. if (!isIe7) {
  86. assertEquals(cssText, fixCssTextForIe(allCssText));
  87. }
  88. }
  89. function testGetAllCssStyleRules() {
  90. var allCssRules = goog.cssom.getAllCssStyleRules();
  91. assertEquals(6, allCssRules.length);
  92. }
  93. function testAddCssText() {
  94. var newCssText = '.css-add-1 { display: block; }';
  95. var newCssNode = goog.cssom.addCssText(newCssText);
  96. assertEquals(document.styleSheets.length, 3);
  97. var allCssText = goog.cssom.getAllCssText();
  98. // In IE7, a CSSRule object gets included twice and replaces another
  99. // existing CSSRule object. We aren't using
  100. // goog.testing.ExpectedFailures since it brings in additional CSS
  101. // which breaks a lot of our expectations about the number of rules
  102. // present in a style sheet.
  103. if (!isIe7) {
  104. // Opera inserts the CSSRule to the first position. And fixCssText
  105. // is also needed to clean up whitespace.
  106. if (goog.userAgent.OPERA) {
  107. assertEquals(newCssText + ' ' + cssText, fixCssTextForIe(allCssText));
  108. } else {
  109. assertEquals(cssText + ' ' + newCssText, fixCssTextForIe(allCssText));
  110. }
  111. }
  112. var cssRules = goog.cssom.getAllCssStyleRules();
  113. assertEquals(7, cssRules.length);
  114. // Remove the new stylesheet now so it doesn't interfere with other
  115. // tests.
  116. newCssNode.parentNode.removeChild(newCssNode);
  117. // Sanity check.
  118. cssRules = goog.cssom.getAllCssStyleRules();
  119. assertEquals(6, cssRules.length);
  120. }
  121. function testAddCssRule() {
  122. // test that addCssRule correctly adds the rule to the style
  123. // sheet.
  124. var styleSheets = goog.cssom.getAllCssStyleSheets();
  125. var styleSheet = styleSheets[3];
  126. var newCssRule = '.css-addCssRule { display: block; }';
  127. var rules = styleSheet.rules || styleSheet.cssRules;
  128. var origNumberOfRules = rules.length;
  129. goog.cssom.addCssRule(styleSheet, newCssRule, 1);
  130. rules = styleSheet.rules || styleSheet.cssRules;
  131. var newNumberOfRules = rules.length;
  132. assertEquals(newNumberOfRules, origNumberOfRules + 1);
  133. // Remove the added rule so we don't mess up other tests.
  134. goog.cssom.removeCssRule(styleSheet, 1);
  135. }
  136. function testAddCssRuleAtPos() {
  137. // test that addCssRule correctly adds the rule to the style
  138. // sheet at the specified position.
  139. var styleSheets = goog.cssom.getAllCssStyleSheets();
  140. var styleSheet = styleSheets[3];
  141. var newCssRule = '.css-addCssRulePos { display: block; }';
  142. var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  143. var origNumberOfRules = rules.length;
  144. // Firefox croaks if we try to insert a CSSRule at an index that
  145. // contains a CSSImport Rule. Since we deal only with CSSStyleRule
  146. // objects, we find the first CSSStyleRule and return its index.
  147. //
  148. // NOTE(user): We could have unified the code block below for all
  149. // browsers but IE6 horribly mangled up the stylesheet by creating
  150. // duplicate instances of a rule when removeCssRule was invoked
  151. // just after addCssRule with the looping construct in. This is
  152. // perfectly fine since IE's styleSheet.rules does not contain
  153. // references to anything but CSSStyleRules.
  154. var pos = 0;
  155. if (styleSheet.cssRules) {
  156. pos = goog.array.findIndex(rules, function(rule) {
  157. return rule.type == goog.cssom.CssRuleType.STYLE;
  158. });
  159. }
  160. goog.cssom.addCssRule(styleSheet, newCssRule, pos);
  161. rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  162. var newNumberOfRules = rules.length;
  163. assertEquals(newNumberOfRules, origNumberOfRules + 1);
  164. // Remove the added rule so we don't mess up other tests.
  165. goog.cssom.removeCssRule(styleSheet, pos);
  166. rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  167. assertEquals(origNumberOfRules, rules.length);
  168. }
  169. function testAddCssRuleNoIndex() {
  170. // How well do we handle cases where the optional index is
  171. // not passed in?
  172. var styleSheets = goog.cssom.getAllCssStyleSheets();
  173. var styleSheet = styleSheets[3];
  174. var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  175. var origNumberOfRules = rules.length;
  176. var newCssRule = '.css-addCssRuleNoIndex { display: block; }';
  177. // Try inserting the rule without specifying an index.
  178. // Make sure we don't throw an exception, and that we added
  179. // the entry.
  180. goog.cssom.addCssRule(styleSheet, newCssRule);
  181. rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  182. var newNumberOfRules = rules.length;
  183. assertEquals(newNumberOfRules, origNumberOfRules + 1);
  184. // Remove the added rule so we don't mess up the other tests.
  185. goog.cssom.removeCssRule(styleSheet, newNumberOfRules - 1);
  186. rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  187. assertEquals(origNumberOfRules, rules.length);
  188. }
  189. function testGetParentStyleSheetAfterGetAllCssStyleRules() {
  190. var cssRules = goog.cssom.getAllCssStyleRules();
  191. var cssRule = cssRules[4];
  192. var parentStyleSheet = goog.cssom.getParentStyleSheet(cssRule);
  193. var styleSheets = goog.cssom.getAllCssStyleSheets();
  194. var styleSheet = styleSheets[3];
  195. assertEquals(styleSheet, parentStyleSheet);
  196. }
  197. function testGetCssRuleIndexInParentStyleSheetAfterGetAllCssStyleRules() {
  198. var cssRules = goog.cssom.getAllCssStyleRules();
  199. var cssRule = cssRules[4];
  200. // Note here that this is correct - IE's styleSheet.rules does not
  201. // contain references to anything but CSSStyleRules while FF and others
  202. // include anything that inherits from the CSSRule interface.
  203. // See http://dev.w3.org/csswg/cssom/#cssrule.
  204. var parentStyleSheet = goog.cssom.getParentStyleSheet(cssRule);
  205. var ruleIndex = goog.isDefAndNotNull(parentStyleSheet.cssRules) ? 2 : 1;
  206. assertEquals(
  207. ruleIndex, goog.cssom.getCssRuleIndexInParentStyleSheet(cssRule));
  208. }
  209. function testGetCssRuleIndexInParentStyleSheetNonStyleRule() {
  210. // IE's styleSheet.rules only contain CSSStyleRules.
  211. if (!goog.userAgent.IE) {
  212. var styleSheets = goog.cssom.getAllCssStyleSheets();
  213. var styleSheet = styleSheets[3];
  214. var newCssRule = '@media print { .css-nonStyle { display: block; } }';
  215. goog.cssom.addCssRule(styleSheet, newCssRule);
  216. var rules = styleSheet.rules || styleSheet.cssRules;
  217. var cssRule = rules[rules.length - 1];
  218. assertEquals(goog.cssom.CssRuleType.MEDIA, cssRule.type);
  219. // Make sure we don't throw an exception.
  220. goog.cssom.getCssRuleIndexInParentStyleSheet(cssRule, styleSheet);
  221. // Remove the added rule.
  222. goog.cssom.removeCssRule(styleSheet, rules.length - 1);
  223. }
  224. }
  225. // Tests the scenario where we have a known stylesheet and index.
  226. function testReplaceCssRuleWithStyleSheetAndIndex() {
  227. var styleSheets = goog.cssom.getAllCssStyleSheets();
  228. var styleSheet = styleSheets[3];
  229. var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  230. var index = 2;
  231. var origCssRule = rules[index];
  232. var origCssText =
  233. fixCssTextForIe(goog.cssom.getCssTextFromCssRule(origCssRule));
  234. goog.cssom.replaceCssRule(origCssRule, replacementCssText, styleSheet, index);
  235. var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  236. var newCssRule = rules[index];
  237. var newCssText = goog.cssom.getCssTextFromCssRule(newCssRule);
  238. assertEquals(replacementCssText, fixCssTextForIe(newCssText));
  239. // Now we need to re-replace our rule, to preserve parity for the other
  240. // tests.
  241. goog.cssom.replaceCssRule(newCssRule, origCssText, styleSheet, index);
  242. var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  243. var nowCssRule = rules[index];
  244. var nowCssText = goog.cssom.getCssTextFromCssRule(nowCssRule);
  245. assertEquals(origCssText, fixCssTextForIe(nowCssText));
  246. }
  247. function testReplaceCssRuleUsingGetAllCssStyleRules() {
  248. var cssRules = goog.cssom.getAllCssStyleRules();
  249. var origCssRule = cssRules[4];
  250. var origCssText =
  251. fixCssTextForIe(goog.cssom.getCssTextFromCssRule(origCssRule));
  252. // notice we don't pass in the stylesheet or index.
  253. goog.cssom.replaceCssRule(origCssRule, replacementCssText);
  254. var styleSheets = goog.cssom.getAllCssStyleSheets();
  255. var styleSheet = styleSheets[3];
  256. var rules = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
  257. var index = goog.isDefAndNotNull(styleSheet.cssRules) ? 2 : 1;
  258. var newCssRule = rules[index];
  259. var newCssText =
  260. fixCssTextForIe(goog.cssom.getCssTextFromCssRule(newCssRule));
  261. assertEquals(replacementCssText, newCssText);
  262. // try getting it the other way around too.
  263. var cssRules = goog.cssom.getAllCssStyleRules();
  264. var newCssRule = cssRules[4];
  265. var newCssText =
  266. fixCssTextForIe(goog.cssom.getCssTextFromCssRule(newCssRule));
  267. assertEquals(replacementCssText, newCssText);
  268. // Now we need to re-replace our rule, to preserve parity for the other
  269. // tests.
  270. goog.cssom.replaceCssRule(newCssRule, origCssText);
  271. var cssRules = goog.cssom.getAllCssStyleRules();
  272. var nowCssRule = cssRules[4];
  273. var nowCssText =
  274. fixCssTextForIe(goog.cssom.getCssTextFromCssRule(nowCssRule));
  275. assertEquals(origCssText, nowCssText);
  276. }