jstemplate_test.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // Copyright 2006 Google Inc.
  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
  12. // implied. See the License for the specific language governing
  13. // permissions and limitations under the License.
  14. /**
  15. * @author Steffen Meschkat (mesch@google.com)
  16. * @fileoverview Unittest and examples for jstemplates.
  17. */
  18. function jstWrap(data, template) {
  19. return jstProcess(new JsEvalContext(data), template);
  20. }
  21. function testJstSelect() {
  22. // Template cardinality from jsselect.
  23. var t = document.getElementById('t1');
  24. var d = {
  25. items: [ 'A', 'B', 'C', '' ]
  26. }
  27. jstWrap(d, t);
  28. var h = t.innerHTML;
  29. var clone = domCloneNode(t);
  30. assertTrue(/>A<\/div>/.test(h));
  31. assertTrue(/>B<\/div>/.test(h));
  32. assertTrue(/>C<\/div>/.test(h));
  33. assertTrue(/><\/div>/.test(h));
  34. // Reprocessing with identical data.
  35. jstWrap(d, t);
  36. assertAttributesMatch(t, clone);
  37. // Reprocessing with changed data.
  38. d.items[1] = 'BB';
  39. jstWrap(d, t);
  40. h = t.innerHTML;
  41. assertTrue(/>A<\/div>/.test(h));
  42. assertFalse(/>B<\/div>/.test(h));
  43. assertTrue(/>BB<\/div>/.test(h));
  44. assertTrue(/>C<\/div>/.test(h));
  45. // Reprocessing with dropped data.
  46. d.items.pop();
  47. d.items.pop();
  48. jstWrap(d, t);
  49. h = t.innerHTML;
  50. assertTrue(/>A<\/div>/.test(h));
  51. assertTrue(/>BB<\/div>/.test(h));
  52. assertFalse(/>C<\/div>/.test(h));
  53. assertFalse(/><\/div>/.test(h));
  54. // Reprocessing with dropped data, once more.
  55. d.items.pop();
  56. jstWrap(d, t);
  57. h = t.innerHTML;
  58. assertTrue(/>A<\/div>/.test(h));
  59. assertFalse(/>BB<\/div>/.test(h));
  60. assertFalse(/>C<\/div>/.test(h));
  61. // Reprocessing with empty data -- the last template instance is
  62. // preserved, and only hidden.
  63. d.items.pop();
  64. jstWrap(d, t);
  65. assertTrue(/>A<\/div>/.test(h));
  66. assertFalse(/>BB<\/div>/.test(h));
  67. assertFalse(/>C<\/div>/.test(h));
  68. // Reprocessing with added data.
  69. d.items.push('D');
  70. jstWrap(d, t);
  71. h = t.innerHTML;
  72. assertFalse(/>A<\/div>/.test(h));
  73. assertTrue(/>D<\/div>/.test(h));
  74. }
  75. function testJstDisplay() {
  76. var t = document.getElementById('t2');
  77. var d = {
  78. display: true
  79. }
  80. jstWrap(d, t);
  81. var h = t.innerHTML;
  82. assertFalse(/display:\s*none/.test(h));
  83. d.display = false;
  84. jstWrap(d, t);
  85. h = t.innerHTML;
  86. assertTrue(/display:\s*none/.test(h));
  87. // Check that 'this' within js expressions is the template node
  88. t = document.getElementById('t2a');
  89. d = {
  90. showId: 'x'
  91. };
  92. jstWrap(d, t);
  93. h = t.innerHTML;
  94. assertFalse(/display:\s*none/.test(h));
  95. d.showId = 'y';
  96. jstWrap(d, t);
  97. h = t.innerHTML;
  98. assertTrue(/display:\s*none/.test(h));
  99. }
  100. function stringContains(str, sub) {
  101. return str.indexOf(sub) != -1;
  102. }
  103. function testJseval() {
  104. var data = {};
  105. var counter = 0;
  106. var ctx = new JsEvalContext(data);
  107. ctx.setVariable("callback1", function() {
  108. ++counter;
  109. });
  110. ctx.setVariable("callback2", function() {
  111. counter *= 2;
  112. });
  113. jstProcess(ctx, document.getElementById('testJseval1'));
  114. assertEquals("testJseval1", 1, counter);
  115. jstProcess(ctx, document.getElementById('testJseval2'));
  116. assertEquals("testJseval2", 4, counter);
  117. }
  118. function testJstValues() {
  119. var t = document.getElementById('t3');
  120. var d = {};
  121. jstWrap(d, t);
  122. var h = t.innerHTML;
  123. assertTrue(stringContains(h, 'http://maps.google.com/'));
  124. var t3a = document.getElementById('t3a');
  125. assertEquals('http://maps.google.com/', t3a.foo.bar.baz);
  126. assertEquals('http://maps.google.com/', t3a.bar);
  127. assertEquals('red', t3a.style.backgroundColor);
  128. }
  129. function testJstTransclude() {
  130. var t = document.getElementById('t4');
  131. var p = document.getElementById('parent');
  132. var d = {};
  133. jstWrap(d, t);
  134. var h = p.innerHTML;
  135. assertTrue(h, stringContains(h, 'http://maps.google.com/'));
  136. }
  137. function assertAttributesMatch(first, second) {
  138. assertEquals('assertAttributesMatch: number of child nodes',
  139. jsLength(first.childNodes), jsLength(second.childNodes));
  140. var b = second.firstChild;
  141. for (var a = first.firstChild; a; a = a.nextSibling) {
  142. var att = a.attributes;
  143. if (att) {
  144. assertTrue(b.attributes != null);
  145. assertEquals('assertAttributesMatch: number of attribute nodes',
  146. att.length, b.attributes.length);
  147. for (var i = 0; i < jsLength(att); i++) {
  148. var a = att[i];
  149. assertEquals('assertAttributesMatch: value of attribute ' + a.name,
  150. a.value, b.getAttribute(a.name));
  151. }
  152. } else {
  153. assertNull(b.attributes);
  154. }
  155. b = b.nextSibling;
  156. }
  157. }
  158. function testJsskip() {
  159. var div = domCreateElement(document, "DIV");
  160. div.innerHTML = [
  161. '<div jseval="outercallback()" jsskip="1">',
  162. '<div jseval="innercallback()">',
  163. '</div>',
  164. '</div>'
  165. ].join('');
  166. var data = {};
  167. var ctx = new JsEvalContext(data);
  168. var outerCalled = false;
  169. ctx.setVariable("outercallback", function() {
  170. outerCalled = true;
  171. });
  172. var innerCalled = false;
  173. ctx.setVariable("innercallback", function() {
  174. innerCalled = true;
  175. });
  176. jstProcess(ctx, div);
  177. assertTrue(outerCalled);
  178. assertFalse(innerCalled);
  179. }
  180. function testScalarContext() {
  181. var t = document.getElementById('testScalarContext');
  182. jstWrap(true, t);
  183. assertTrue(/>true</.test(t.innerHTML));
  184. jstWrap(false, t);
  185. assertTrue(/>false</.test(t.innerHTML));
  186. jstWrap(0, t);
  187. assertTrue(/>0</.test(t.innerHTML));
  188. jstWrap("foo", t);
  189. assertTrue(/>foo</.test(t.innerHTML));
  190. jstWrap(undefined, t);
  191. assertTrue(/>undefined</.test(t.innerHTML));
  192. jstWrap(null, t);
  193. assertTrue(/>null</.test(t.innerHTML));
  194. }
  195. function testJstLoadTemplate() {
  196. var wrapperId = 'testJstLoadTemplateWrapper';
  197. var id = 'testJstLoadTemplate';
  198. jstLoadTemplate_(document, '<div id="' + id + '">content</div>', wrapperId);
  199. var wrapperElem = document.getElementById(wrapperId);
  200. assertTrue('Expected wrapper element to be in document',
  201. !!wrapperElem);
  202. var newTemplate = document.getElementById(id);
  203. assertTrue('Expected newly loaded template to be in document',
  204. !!newTemplate);
  205. assertTrue('Expected wrapper to be grandparent of template',
  206. newTemplate.parentNode.parentNode == wrapperElem);
  207. // Make sure the next template loaded with the same wrapper id re-uses the
  208. // wrapper element.
  209. var id2 = 'testJstLoadTemplate2';
  210. jstLoadTemplate_(document, '<div id="' + id2 + '">content</div>', wrapperId);
  211. var newTemplate2 = document.getElementById(id2);
  212. assertTrue('Expected newly loaded template to be in document',
  213. !!newTemplate2);
  214. assertTrue('Expected wrapper to be grandparent of template',
  215. newTemplate2.parentNode.parentNode == wrapperElem);
  216. }
  217. function testJstGetTemplateFromDom() {
  218. var element;
  219. // Get by id a template in the document
  220. // Success
  221. element = jstGetTemplate('t1');
  222. assertTrue("Asserted jstGetTemplate('t1') to return a dom element",
  223. !!element);
  224. // Failure
  225. element = jstGetTemplate('asdf');
  226. assertFalse("Asserted jstGetTemplate('asdf') to return null",
  227. !!element);
  228. }
  229. function testJstGetTemplateFromFunction() {
  230. var element;
  231. // Fetch a jstemplate by id from within a html string, passed via a function.
  232. function returnHtmlWithId(id) {
  233. var html =
  234. '<div>' +
  235. '<div id="' + id + '">Here is the template</div>' +
  236. '</div>';
  237. return html;
  238. }
  239. // Success
  240. element = jstGetTemplate('template',
  241. partial(returnHtmlWithId, 'template'));
  242. assertTrue("Expected jstGetTemplate('template') to return a dom element",
  243. !!element);
  244. // Failure
  245. element = jstGetTemplate('asdf',
  246. partial(returnHtmlWithId, 'zxcv'));
  247. assertFalse("Expected jstGetTemplate('zxcv') to return null",
  248. !!element);
  249. }
  250. function testPrepareNode() {
  251. var id, node;
  252. // Reset the cache so we're testing from a known state.
  253. JstProcessor.jstCache_ = {};
  254. JstProcessor.jstCache_[0] = {};
  255. // Skip pre-processed nodes. Preprocessed nodes are those with a
  256. // PROP_jstcache property.
  257. var t = document.getElementById('t1');
  258. var caches = [];
  259. caches.push(JstProcessor.prepareNode_(t));
  260. caches.push(JstProcessor.prepareNode_(t));
  261. assertEquals('The same cache should be returned on each call to prepareNode',
  262. caches[0], caches[1]);
  263. // Preprocessing a node with a jst attribute should return a valid struct
  264. id = 'testPrepareNodeWithAttributes';
  265. jstLoadTemplate_(document, '<div id="' + id + '" jsskip="1"></div>');
  266. node = document.getElementById(id);
  267. var cache = JstProcessor.prepareNode_(node);
  268. try {
  269. var jsskip = cache['jsskip']({}, {});
  270. } catch (e) {
  271. fail('Exception when evaluating jsskip from cache');
  272. }
  273. assertEquals(1, jsskip);
  274. }
  275. function testPrepareNodeWithNoAttributes() {
  276. // Preprocessing a node with no jst attributes should return null
  277. var id = 'testPrepareNodeNoAttributes';
  278. jstLoadTemplate_(document, '<div id="' + id + '"></div>');
  279. var node = document.getElementById(id);
  280. assertEquals('prepareNode with no jst attributes should return default',
  281. JstProcessor.jstcache_[0], JstProcessor.prepareNode_(node));
  282. }
  283. function testJsVars() {
  284. var template = document.createElement('div');
  285. document.body.appendChild(template);
  286. template.innerHTML = '<div jsvars="foo:\'foo\';bar:true;$baz:1"></div>';
  287. var context = new JsEvalContext;
  288. jstProcess(context, template);
  289. assertEquals('foo', context.getVariable('foo'));
  290. assertEquals(1, context.getVariable('$baz'));
  291. assertTrue(context.getVariable('bar'));
  292. assertUndefined(context.getVariable('foobar'));
  293. }
  294. function testCacheReuse() {
  295. var template = document.createElement('div');
  296. document.body.appendChild(template);
  297. template.innerHTML =
  298. '<div jsvars="foo:\'foo\';bar:true;$baz:1"></div>' +
  299. '<span jsvars="foo:\'foo\';bar:true;$baz:1"></span>';
  300. JstProcessor.prepareTemplate_(template);
  301. assertEquals(template.firstChild.getAttribute(ATT_jstcache),
  302. template.lastChild.getAttribute(ATT_jstcache));
  303. }