soy_test.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // Copyright 2011 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.soyTest');
  15. goog.setTestOnly('goog.soyTest');
  16. goog.require('goog.dom');
  17. goog.require('goog.dom.NodeType');
  18. goog.require('goog.dom.TagName');
  19. goog.require('goog.functions');
  20. goog.require('goog.soy');
  21. /** @suppress {extraRequire} */
  22. goog.require('goog.soy.testHelper');
  23. goog.require('goog.testing.PropertyReplacer');
  24. goog.require('goog.testing.jsunit');
  25. var stubs;
  26. function setUp() {
  27. stubs = new goog.testing.PropertyReplacer();
  28. }
  29. function tearDown() {
  30. stubs.reset();
  31. }
  32. function testRenderHtml() {
  33. var testDiv = goog.dom.createElement(goog.dom.TagName.DIV);
  34. goog.soy.renderHtml(testDiv, example.sanitizedHtmlTemplate());
  35. assertEquals('hello <b>world</b>', testDiv.innerHTML.toLowerCase());
  36. }
  37. function testRenderElement() {
  38. var testDiv = goog.dom.createElement(goog.dom.TagName.DIV);
  39. goog.soy.renderElement(testDiv, example.multiRootTemplate, {name: 'Boo'});
  40. assertEquals('<div>Hello</div><div>Boo</div>', elementToInnerHtml(testDiv));
  41. }
  42. function testRenderElementWithNoTemplateData() {
  43. var testDiv = goog.dom.createElement(goog.dom.TagName.DIV);
  44. goog.soy.renderElement(testDiv, example.noDataTemplate);
  45. assertEquals('<div>Hello</div>', elementToInnerHtml(testDiv));
  46. }
  47. function testRenderAsFragmentTextNode() {
  48. var fragment =
  49. goog.soy.renderAsFragment(example.textNodeTemplate, {name: 'Boo'});
  50. assertEquals(goog.dom.NodeType.TEXT, fragment.nodeType);
  51. assertEquals('Boo', fragmentToHtml(fragment));
  52. }
  53. function testRenderAsFragmentInjectedData() {
  54. var fragment = goog.soy.renderAsFragment(
  55. example.injectedDataTemplate, {name: 'Boo'}, {name: 'ijBoo'});
  56. assertEquals(goog.dom.NodeType.TEXT, fragment.nodeType);
  57. assertEquals('BooijBoo', fragmentToHtml(fragment));
  58. }
  59. function testRenderAsFragmentSingleRoot() {
  60. var fragment =
  61. goog.soy.renderAsFragment(example.singleRootTemplate, {name: 'Boo'});
  62. assertEquals(goog.dom.NodeType.ELEMENT, fragment.nodeType);
  63. assertEquals(String(goog.dom.TagName.SPAN), fragment.tagName);
  64. assertEquals('Boo', fragment.innerHTML);
  65. }
  66. function testRenderAsFragmentMultiRoot() {
  67. var fragment =
  68. goog.soy.renderAsFragment(example.multiRootTemplate, {name: 'Boo'});
  69. assertEquals(goog.dom.NodeType.DOCUMENT_FRAGMENT, fragment.nodeType);
  70. assertEquals('<div>Hello</div><div>Boo</div>', fragmentToHtml(fragment));
  71. }
  72. function testRenderAsFragmentNoData() {
  73. var fragment = goog.soy.renderAsFragment(example.noDataTemplate);
  74. assertEquals(goog.dom.NodeType.ELEMENT, fragment.nodeType);
  75. assertEquals('<div>Hello</div>', fragmentToHtml(fragment));
  76. }
  77. function testRenderAsElementTextNode() {
  78. var elem = goog.soy.renderAsElement(example.textNodeTemplate, {name: 'Boo'});
  79. assertEquals(goog.dom.NodeType.ELEMENT, elem.nodeType);
  80. assertEquals(String(goog.dom.TagName.DIV), elem.tagName);
  81. assertEquals('Boo', elementToInnerHtml(elem));
  82. }
  83. function testRenderAsElementInjectedData() {
  84. var elem = goog.soy.renderAsElement(
  85. example.injectedDataTemplate, {name: 'Boo'}, {name: 'ijBoo'});
  86. assertEquals(goog.dom.NodeType.ELEMENT, elem.nodeType);
  87. assertEquals(String(goog.dom.TagName.DIV), elem.tagName);
  88. assertEquals('BooijBoo', elementToInnerHtml(elem));
  89. }
  90. function testRenderAsElementSingleRoot() {
  91. var elem =
  92. goog.soy.renderAsElement(example.singleRootTemplate, {name: 'Boo'});
  93. assertEquals(goog.dom.NodeType.ELEMENT, elem.nodeType);
  94. assertEquals(String(goog.dom.TagName.SPAN), elem.tagName);
  95. assertEquals('Boo', elementToInnerHtml(elem));
  96. }
  97. function testRenderAsElementMultiRoot() {
  98. var elem = goog.soy.renderAsElement(example.multiRootTemplate, {name: 'Boo'});
  99. assertEquals(goog.dom.NodeType.ELEMENT, elem.nodeType);
  100. assertEquals(String(goog.dom.TagName.DIV), elem.tagName);
  101. assertEquals('<div>Hello</div><div>Boo</div>', elementToInnerHtml(elem));
  102. }
  103. function testRenderAsElementWithNoData() {
  104. var elem = goog.soy.renderAsElement(example.noDataTemplate);
  105. assertEquals('Hello', elementToInnerHtml(elem));
  106. }
  107. function testConvertToElement() {
  108. var elem = goog.soy.convertToElement(example.sanitizedHtmlTemplate());
  109. assertEquals(goog.dom.NodeType.ELEMENT, elem.nodeType);
  110. assertEquals(String(goog.dom.TagName.DIV), elem.tagName);
  111. assertEquals('hello <b>world</b>', elem.innerHTML.toLowerCase());
  112. }
  113. /**
  114. * Asserts that the function throws an error for unsafe templates.
  115. * @param {Function} function Callback to test.
  116. */
  117. function assertUnsafeTemplateOutputErrorThrown(func) {
  118. stubs.set(goog.asserts, 'ENABLE_ASSERTS', true);
  119. assertContains(
  120. 'Soy template output is unsafe for use as HTML',
  121. assertThrows(func).message);
  122. stubs.set(goog.asserts, 'ENABLE_ASSERTS', false);
  123. assertEquals('zSoyz', func());
  124. }
  125. function testAllowButEscapeUnsanitizedText() {
  126. var div = goog.dom.createElement(goog.dom.TagName.DIV);
  127. goog.soy.renderElement(div, example.unsanitizedTextTemplate);
  128. assertEquals('I &lt;3 Puppies &amp; Kittens', div.innerHTML);
  129. var fragment = goog.soy.renderAsFragment(example.unsanitizedTextTemplate);
  130. assertEquals('I <3 Puppies & Kittens', fragment.nodeValue);
  131. assertEquals(
  132. 'I &lt;3 Puppies &amp; Kittens',
  133. goog.soy.renderAsElement(example.unsanitizedTextTemplate).innerHTML);
  134. }
  135. function testRejectSanitizedCss() {
  136. assertUnsafeTemplateOutputErrorThrown(function() {
  137. goog.soy.renderAsElement(example.sanitizedCssTemplate);
  138. });
  139. }
  140. function testRejectSanitizedCss() {
  141. assertUnsafeTemplateOutputErrorThrown(function() {
  142. return goog.soy
  143. .renderAsElement(example.templateSpoofingSanitizedContentString)
  144. .innerHTML;
  145. });
  146. }
  147. function testRejectStringTemplatesWhenModeIsSet() {
  148. stubs.set(goog.soy, 'REQUIRE_STRICT_AUTOESCAPE', true);
  149. assertUnsafeTemplateOutputErrorThrown(function() {
  150. return goog.soy.renderAsElement(example.noDataTemplate).innerHTML;
  151. });
  152. }
  153. function testAcceptSanitizedHtml() {
  154. assertEquals(
  155. 'Hello World',
  156. goog.dom.getTextContent(
  157. goog.soy.renderAsElement(example.sanitizedHtmlTemplate)));
  158. }
  159. function testRejectSanitizedHtmlAttributes() {
  160. // Attributes context has nothing to do with html.
  161. assertUnsafeTemplateOutputErrorThrown(function() {
  162. return goog.dom.getTextContent(
  163. goog.soy.renderAsElement(example.sanitizedHtmlAttributesTemplate));
  164. });
  165. }
  166. function testAcceptNonObject() {
  167. // Some templates, or things that spoof templates in unit tests, might return
  168. // non-strings in unusual cases.
  169. assertEquals(
  170. 'null', goog.dom.getTextContent(
  171. goog.soy.renderAsElement(goog.functions.constant(null))));
  172. }
  173. function testDebugAssertionWithBadFirstTag() {
  174. try {
  175. goog.soy.renderAsElement(example.tableRowTemplate);
  176. // Expect no exception in production code.
  177. assert(!goog.DEBUG);
  178. } catch (e) {
  179. // Expect exception in debug code.
  180. assert(goog.DEBUG);
  181. // Make sure to let the developer know which tag caused the problem.
  182. assertContains('<tr>', e.message);
  183. }
  184. try {
  185. goog.soy.renderAsFragment(example.tableRowTemplate);
  186. // Expect no exception in production code.
  187. assert(!goog.DEBUG);
  188. } catch (e) {
  189. // Expect exception in debug code.
  190. assert(goog.DEBUG);
  191. // Make sure to let the developer know which tag caused the problem.
  192. assertContains('<tr>', e.message);
  193. }
  194. try {
  195. goog.soy.renderAsElement(example.colGroupTemplateCaps);
  196. // Expect no exception in production code.
  197. assert(!goog.DEBUG);
  198. } catch (e) {
  199. // Expect exception in debug code.
  200. assert(goog.DEBUG);
  201. // Make sure to let the developer know which tag caused the problem.
  202. assertContains('<COLGROUP>', e.message);
  203. }
  204. }