1 // Copyright 2006 Google Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 * @author Steffen Meschkat (mesch@google.com)
16 * @fileoverview Unittest and examples for jstemplates.
19 function jstWrap(data, template) {
20 return jstProcess(new JsEvalContext(data), template);
23 function testJstSelect() {
24 // Template cardinality from jsselect.
25 var t = document.getElementById('t1');
27 items: [ 'A', 'B', 'C', '' ]
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));
38 // Reprocessing with identical data.
40 assertAttributesMatch(t, clone);
42 // Reprocessing with changed data.
47 assertTrue(/>A<\/div>/.test(h));
48 assertFalse(/>B<\/div>/.test(h));
49 assertTrue(/>BB<\/div>/.test(h));
50 assertTrue(/>C<\/div>/.test(h));
52 // Reprocessing with dropped data.
57 assertTrue(/>A<\/div>/.test(h));
58 assertTrue(/>BB<\/div>/.test(h));
59 assertFalse(/>C<\/div>/.test(h));
60 assertFalse(/><\/div>/.test(h));
62 // Reprocessing with dropped data, once more.
66 assertTrue(/>A<\/div>/.test(h));
67 assertFalse(/>BB<\/div>/.test(h));
68 assertFalse(/>C<\/div>/.test(h));
70 // Reprocessing with empty data -- the last template instance is
71 // preserved, and only hidden.
75 assertTrue(/>A<\/div>/.test(h));
76 assertFalse(/>BB<\/div>/.test(h));
77 assertFalse(/>C<\/div>/.test(h));
79 // Reprocessing with added data.
83 assertFalse(/>A<\/div>/.test(h));
84 assertTrue(/>D<\/div>/.test(h));
87 function testJstDisplay() {
88 var t = document.getElementById('t2');
95 assertFalse(/display:\s*none/.test(h));
101 assertTrue(/display:\s*none/.test(h));
103 // Check that 'this' within js expressions is the template node
104 t = document.getElementById('t2a');
111 assertFalse(/display:\s*none/.test(h));
117 assertTrue(/display:\s*none/.test(h));
120 function stringContains(str, sub) {
121 return str.indexOf(sub) != -1;
124 function testJseval() {
128 var ctx = new JsEvalContext(data);
129 ctx.setVariable("callback1", function() {
132 ctx.setVariable("callback2", function() {
136 jstProcess(ctx, document.getElementById('testJseval1'));
137 assertEquals("testJseval1", 1, counter);
139 jstProcess(ctx, document.getElementById('testJseval2'));
140 assertEquals("testJseval2", 4, counter);
143 function testJstValues() {
144 var t = document.getElementById('t3');
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);
155 function testJstTransclude() {
156 var t = document.getElementById('t4');
157 var p = document.getElementById('parent');
161 assertTrue(h, stringContains(h, 'http://maps.google.com/'));
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;
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++) {
176 assertEquals('assertAttributesMatch: value of attribute ' + a.name,
177 a.value, b.getAttribute(a.name));
180 assertNull(b.attributes);
186 function testJsskip() {
187 var div = domCreateElement(document, "DIV");
189 '<div jseval="outercallback()" jsskip="1">',
190 '<div jseval="innercallback()">',
196 var ctx = new JsEvalContext(data);
197 var outerCalled = false;
198 ctx.setVariable("outercallback", function() {
201 var innerCalled = false;
202 ctx.setVariable("innercallback", function() {
205 jstProcess(ctx, div);
207 assertTrue(outerCalled);
208 assertFalse(innerCalled);
211 function testScalarContext() {
212 var t = document.getElementById('testScalarContext');
215 assertTrue(/>true</.test(t.innerHTML));
218 assertTrue(/>false</.test(t.innerHTML));
221 assertTrue(/>0</.test(t.innerHTML));
224 assertTrue(/>foo</.test(t.innerHTML));
226 jstWrap(undefined, t);
227 assertTrue(/>undefined</.test(t.innerHTML));
230 assertTrue(/>null</.test(t.innerHTML));
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',
240 var newTemplate = document.getElementById(id);
241 assertTrue('Expected newly loaded template to be in document',
243 assertTrue('Expected wrapper to be grandparent of template',
244 newTemplate.parentNode.parentNode == wrapperElem);
246 // Make sure the next template loaded with the same wrapper id re-uses the
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',
253 assertTrue('Expected wrapper to be grandparent of template',
254 newTemplate2.parentNode.parentNode == wrapperElem);
257 function testJstGetTemplateFromDom() {
259 // Get by id a template in the document
261 element = jstGetTemplate('t1');
262 assertTrue("Asserted jstGetTemplate('t1') to return a dom element",
265 element = jstGetTemplate('asdf');
266 assertFalse("Asserted jstGetTemplate('asdf') to return null",
270 function testJstGetTemplateFromFunction() {
272 // Fetch a jstemplate by id from within a html string, passed via a function.
273 function returnHtmlWithId(id) {
276 '<div id="' + id + '">Here is the template</div>' +
281 element = jstGetTemplate('template',
282 partial(returnHtmlWithId, 'template'));
283 assertTrue("Expected jstGetTemplate('template') to return a dom element",
287 element = jstGetTemplate('asdf',
288 partial(returnHtmlWithId, 'zxcv'));
289 assertFalse("Expected jstGetTemplate('zxcv') to return null",
293 function testPrepareNode() {
295 // Reset the cache so we're testing from a known state.
296 JstProcessor.jstCache_ = {};
297 JstProcessor.jstCache_[0] = {};
299 // Skip pre-processed nodes. Preprocessed nodes are those with a
300 // PROP_jstcache property.
301 var t = document.getElementById('t1');
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]);
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);
314 var jsskip = cache['jsskip']({}, {});
316 fail('Exception when evaluating jsskip from cache');
318 assertEquals(1, jsskip);
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));
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>';
337 var context = new JsEvalContext;
338 jstProcess(context, template);
340 assertEquals('foo', context.getVariable('foo'));
341 assertEquals(1, context.getVariable('$baz'));
342 assertTrue(context.getVariable('bar'));
343 assertUndefined(context.getVariable('foobar'));
347 function testCacheReuse() {
348 var template = document.createElement('div');
349 document.body.appendChild(template);
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));