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
));