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