Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
389 lines (310 sloc) 22.3 KB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 />
<title>jQuery-tmpl tests</title>
<!-- links to qunit + jquery -->
<link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script>
<script src="jquery.tmpl.js"></script>
<script src="jquery.tmpl.autocache.js"></script>
<script id="FooTemplate" type="text/html">foo-{{= one }}</script>
<script>
//QUnit.done = function () { $('.fail ol').show(); };
var O = {
one: "first",
two: "second",
count: 5,
v: "test",
arr: ["AA","BB","CC"],
dict: {leovinus:"this",scraliontis:"that",brobostigon:"other"},
fun: function () {
return 'RETURNED';
}
};
var R = function ( tmpl, data ) {
try {
return jQuery.tmpl( tmpl ).call( data, jQuery, data, 0 );
}
catch ( e ) {
if ( typeof e === 'string' ) {
return 'ERROR: ' + e;
}
return e;
}
};
function test_handler( test_name, res, exp ) {
var is_err = ($.isFunction(exp) && exp.prototype instanceof Error);
if ( is_err && res instanceof exp ) {
ok( res instanceof exp, test_name );
}
else {
same( res, exp, test_name );
}
}
// these are used throughout to test if tag blocks suppress them
jQuery.tmplcmd.syntax_error = { prefix: "throw SyntaxError('test syntax error');" };
jQuery.tmplcmd.reference_error = { prefix: "throw ReferenceError('test reference error');" };
jQuery.tmplcmd.type_error = { prefix: "throw TypeError('test type error');" };
test("Basics", function() {
ok( jQuery.isFunction(jQuery.tmpl), "jQuery.tmpl is a function" );
ok( jQuery.isFunction(jQuery.tmpl('<div/>')), "jQuery.tmpl returns a function" );
ok( jQuery.isArray(jQuery.tmpl('<div/>', {})), "jQuery.tmpl with data returns an array" );
test_handler( 'plain text passes through untouched', R('lorem ipsum',O), 'lorem ipsum' );
test_handler( 'whitespace is left untouched', R('\n\tlorem\n\n\tipsum \t',O), '\n\tlorem\n\n\tipsum \t' );
ok( jQuery.tmpl( 'some text' ).call(), "jQuery.tmpl does not require parameters" );
ok( jQuery('<script type="text/html"><div>some text</div><\x2fscript>').render().html(), "jQuery.fn.render does not require parameters" );
// throw errors with incomplete syntax
test_handler( 'empty tag', R("{{}}",O), '{{}}' );
test_handler( 'empty tag (with whitespace)', R("{{ }}"), '{{ }}' );
test_handler( 'empty tag (with tabs whitespace)', R("{{\t\t}}"), '{{\t\t}}' );
test_handler( 'multi word variable tag', R("{{= a b c }}"), SyntaxError );
test_handler( 'incorrect nesting', R("{{ if 1 }}{{ if 1 }}{{ /if }}",O), SyntaxError );
test_handler( 'incorrect nesting (extra /if)', R("{{ if 1 }}{{ /if }}{{ /if }}",O), SyntaxError );
test_handler( 'incorrect nesting (but terminated)', R("{{ if 1 }}{{ each arr }}{{ /if }}{{ /each }}",O), SyntaxError );
test_handler( 'ignore malformedness 1', R("a {{ one } b",O), 'a {{ one } b' );
test_handler( 'ignore malformedness 2', R("${ one }} {{ two }",O), 'first} {{ two }' );
test_handler( 'ignore malformedness 3', R('{{ one }',O), '{{ one }' );
// newlines should work because: {{= foo + "\n" }}
// and they have whitespace management benefits
test_handler( "newlines do not kill tags", R('{{\n= \none\n }}',O), 'first');
test_handler( "newlines in strings don't kill tags", R('{{= "on\ne" }}',O), 'on\ne' );
test_handler( "returns do not kill tags", R('{{\r= \r\none\r\n }}',O), 'first');
test_handler( "returns in strings don't kill tags", R('{{= "on\re" }}',O), 'on\re' );
test_handler( "slashes in strings don't kill tags", R('{{= "on\\e" }}',O), 'on\\e');
test_handler( "newlines don't kill parsing", R('a\nb\nc{{= 8 }}.'), 'a\nb\nc8.');
// TODO: this is the data object (contexts)
jQuery.getText = function ( str ) { return str.toUpperCase(); };
jQuery.tmplcmd['trans'] = { prefix: "_.push($.getText($ARGS));" };
test_handler( "creating new tags works", R('{{trans "translate" }}'), 'TRANSLATE' );
test_handler( "$ cannot be used by data", R('{{= $ }}', {'$':'foo'}), TypeError );
test_handler( "_ can by used by data", R('{{= _ }}', {'_':'foo'}), 'foo' );
jQuery.tmplcmd['_'] = jQuery.tmplcmd['trans'];
test_handler( "_ can by assigned a tag", R('{{_ "translate" }}', {}), 'TRANSLATE' );
// javascript operations
test_handler( "JS: string concatination", R('{{= one + "foo" }}',O), "firstfoo" );
test_handler( "JS: adding", R('{{= 1 + 5 }}',O), "6" );
test_handler( "JS: subtracting", R('{{= 9 - 5 }}',O), "4" );
test_handler( "JS: modulo", R('{{= 5 % 2 }}',O), "1" );
test_handler( "JS: unary minus", R('{{= -n }}',{n:10}), "-10" );
test_handler( "JS: unary plus", R('{{= +n }}',{n:"10"}), "10" );
test_handler( "JS: in operator", R('{{= "bar" in foo }}',{foo:{bar:'baz'}}), "true" );
test_handler( "JS: instanceof operator", R('{{= foo instanceof Date }}',{foo:new Date()}), "true" );
test_handler( "JS: typeof operator", R('{{= typeof "str" }}',{}), "string" );
// TODO: regurlar exporessions ?
test_handler( "JS: bitwise AND", R('{{= n & 1 }}',{n:5}), "1" );
test_handler( "JS: bitwise OR", R('{{= n | 1 }}',{n:4}), "5" );
test_handler( "JS: bitwise XOR", R('{{= n ^ 1 }}',{n:5}), "4" );
test_handler( "JS: bitwise NOT", R('{{= ~n }}',{n:5}), "-6" );
test_handler( "JS: left shift", R('{{= n << 1 }}',{n:5}), "10" );
test_handler( "JS: right shift", R('{{= n >> 1 }}',{n:5}), "2" );
test_handler( "JS: zero-fill right shift", R('{{= n >>> 1 }}',{n:5}), "2" );
test_handler( "JS: comparing ==", R('{{= 1 == 5 }}',O), "false" );
test_handler( "JS: comparing !=", R('{{= 1 != 5 }}',O), "true" );
test_handler( "JS: comparing ===", R('{{= 5 === 5 }}',O), "true" );
test_handler( "JS: comparing !==", R('{{= 5 !== 5 }}',O), "false" );
test_handler( "JS: comparing >=", R('{{= 1 >= 5 }}',O), "false" );
test_handler( "JS: comparing >", R('{{= 1 > 5 }}',O), "false" );
test_handler( "JS: comparing <=", R('{{= 1 <= 5 }}',O), "true" );
test_handler( "JS: comparing <", R('{{= 1 < 5 }}',O), "true" );
test_handler( "JS: Logical OR", R('{{= zero || "FALSY" }}',{ zero: 0 }), "FALSY" );
test_handler( "JS: Logical AND", R('{{= zero && "TRUEY" }}',{ zero: 1 }), "TRUEY" );
test_handler( "JS: Conditional Operator", R('{{= zero ? "zero" : "other" }}',{ zero: 1 }), "zero" );
test_handler( "JS: Unary logical NOT", R('{{= !zero }}',{ zero: 1 }), "false" );
test_handler( "bracketed accessors work", R('{{= foo["bar"] }}',{foo:{bar:'baz'}}), 'baz' );
test_handler( "bracketed accessors work (single string)", R("{{= foo['bar'] }}",{foo:{bar:'baz'}}), 'baz' );
// illegal operators
test_handler( "Disallow incremental assignment", R('{{= a += 1 }}',O), SyntaxError );
test_handler( "Disallow decremental assignment", R('{{= a -= 1 }}',O), SyntaxError );
test_handler( "Disallow multiply assignment", R('{{= a *= 1 }}',O), SyntaxError );
test_handler( "Disallow division assignment", R('{{= a /= 1 }}',O), SyntaxError );
test_handler( "Disallow left shift assignment", R('{{= a <<= 1 }}',O), SyntaxError );
test_handler( "Disallow right shift assignment", R('{{= a >>= 1 }}',O), SyntaxError );
test_handler( "Disallow zero-fill right shift assignment", R('{{= a >>>= 1 }}',O), SyntaxError );
test_handler( "Disallow bitwise AND assignment", R('{{= a &= 1 }}',O), SyntaxError );
test_handler( "Disallow bitwise OR assignment", R('{{= a |= 1 }}',O), SyntaxError );
test_handler( "Disallow bitwise XOR assignment", R('{{= a ^= 1 }}',O), SyntaxError );
test_handler( "Disallow literal object creation", R('{{= { a:"a"} }}',O), SyntaxError );
test_handler( "Disallow literal array creation", R('{{= [1,2,3] }}',O), SyntaxError );
test_handler( "Disallow decrement", R('{{= --a }}',{a:1}), SyntaxError );
test_handler( "Disallow assignments", R('{{= (a = 2) }}',{a:1}), SyntaxError );
// reserved words
test_handler( "Disallow new operator", R('{{= new Object() }}',{}), SyntaxError );
test_handler( "Disallow delete operator", R('{{= delete a }}',{a:1}), SyntaxError );
test_handler( "Disallow function operator", R('{{= function(){} }}',{}), SyntaxError );
test_handler( "Disallow return", R('{{= return a }}',{a:1}), SyntaxError );
test_handler( "Disallow for", R('{{= for a }}',{a:1}), SyntaxError );
test_handler( "Disallow do/while", R('{{= do{ a }while(a) }}',{a:1}), SyntaxError );
test_handler( "Disallow if", R('{{= if a }}',{a:1}), SyntaxError );
test_handler( "Disallow try/catch", R('{{= try{b.s}catch(e){} }}',{a:1}), SyntaxError );
test_handler( "Disallow return keyword", R('{{= return a }}',{a:1}), SyntaxError );
test_handler( "Disallow with keyword", R('{{= with (s) }}',{a:1}), SyntaxError );
test_handler( "Disallow throw keyword", R('{{= throw "foo" }}',{a:1}), SyntaxError );
// test errors are passed back correctly
test_handler( 'errors are passed back correctly (syntax)', R("{{ syntax_error }}",O), SyntaxError );
test_handler( 'errors are passed back correctly (reference)', R("{{ reference_error }}",O), ReferenceError );
test_handler( 'errors are passed back correctly (type)', R("{{ type_error }}",O), TypeError );
});
test("Comments", function() {
test_handler( "comments are removed", R('A{# comments test #}B',O), "AB" );
test_handler( "comments are removed (2)", R('{# inky #}foo{# blinky #}', O), 'foo' );
test_handler( "comments may include string of comments", R('A{# comments "#}" test #}B',O), "AB" );
test_handler( "comments cannot nest other comments", R('A{# C{# E #}D #}B',O), "AD #}B" );
test_handler( "comments may include strings with escapes (double)", R('A{# comments "str\"ing" test #}B',O), "AB" );
test_handler( "comments may include strings with escapes (single)", R("A{# comments 'str\'ing' test #}B",O), "AB" );
test_handler( "comments may include tags", R("A{# {{= v }} #}B",O), "AB" );
test_handler( "comments may span lines", R("A{# \ncomments test\n #}B",O), "AB" );
test_handler( "comments may contain invalid content (invalid tag)", R('1{# {{ INVALID_TAG }} #}2', O), '12' );
test_handler( "comments may contain invalid content (stray end tag)", R('1{# {{/if}} #}2', O), '12' );
test_handler( "comments may contain invalid content (stray else)", R('1{# {{else}} #}2', O), '12' );
test_handler( "comments may contain invalid content (invalid javascript)", R('1{# {{if ...}} #}2', O), '12' );
});
test("Variables", function() {
test_handler( "variable replacement", R('{{= one }}',O), "first" );
test_handler( "many variables work", R('{{= one }}/{{= two }}',O), "first/second" );
test_handler( "alternative variable syntax", R('${ one }',O), "first" );
test_handler( "many variables work with alt syntax", R('${ one }/${ two }',O), "first/second" );
test_handler( "basic string output (double)", R('{{= "string" }}',O), "string" );
test_handler( "basic string output (single)", R("{{= 'string' }}",O), "string" );
test_handler( "string quote escapes (double)", R('{{= "str\\"i\\"ng" }}',O), 'str"i"ng' );
test_handler( "string quote escapes (single)", R("{{= 'str\\'i\\'ng' }}",O), "str'i'ng" );
test_handler( "string output with tag", R('{{= "{{ tag }}" }}',O), "{{ tag }}" );
test_handler( "string output with end of tag", R('{{= "}}" }}',O), "}}" );
test_handler( 'empty variable tag (with tabs whitespace)', R("{{=\t\t}}", "self"), 'self' );
test_handler( 'empty variable tag', R("{{= }}", "self"), 'self' );
test_handler( 'empty variable tag (with space)', R("{{=}}", "self"), 'self' );
test_handler( "variable lookup error suppression", R('{{= is_undefined }}', O), '' );
test_handler( "variable lookup error suppression (with member)", R('{{= is_undefined.member }}', O), '' );
// jQuery.tmpl.ERROR_STRING = "ILLEGAL"
// test_handler( "variable lookup error suppression string", R('{{= foo.bar }}'), 'INVALID' );
test_handler( "falsy values are correctly rendered (0)", R('{{= 0 }}'), '0' );
test_handler( "falsy values are correctly rendered (false)", R('{{= false }}'), 'false' );
test_handler( "falsy values are correctly rendered (null)", R('{{= zero }}'), '' ); // it's debatable what we want here
test_handler( "falsy values are correctly rendered (undefined)", R('{{= undefined }}'), '' );
test_handler( "falsy values are correctly rendered (\"\")", R('{{= "" }}'), '' );
test_handler( "falsy values are correctly rendered ('')", R("{{= '' }}"), '' );
test_handler( "falsy lookups are correctly rendered (false)", R('{{= zero }}', {zero:0}), '0' );
test_handler( "falsy lookups are correctly rendered (false)", R('{{= zero }}', {zero:false}), 'false' );
test_handler( "falsy lookups are correctly rendered (null)", R('{{= zero }}', {zero:null}), '' ); // it's debatable what we want here
test_handler( "falsy lookups are correctly rendered (undefined)", R('{{= zero }}', {zero:undefined}), '' );
test_handler( "falsy lookups are correctly rendered ('')", R('{{= zero }}', {zero:""}), '' );
// test_handler( "`this` on empty object is (probably) window", R('{{= this }}', {}), window.toString() );
test_handler( "variable and text (1)", R('A{{= one }}', O), 'Afirst' );
test_handler( "variable and text (2)", R('{{= one }}B', O), 'firstB' );
test_handler( "variable and text (3)", R('A{{= one }}B', O), 'AfirstB' );
test_handler( "lookups work for submembers", R('{{= a.b.c }}', {a:{b:{c:"abc"}}}), 'abc' );
test_handler( "error suppression works for submembers", R('{{= a.b.c }}', {a:{b:{c:"abc"}}}), 'abc' );
test_handler( "functions can be called with in tags", R('{{= foo() }}', { foo:function(s){ return "bar"; }}), 'bar' );
test_handler( "functions pass strings correctly", R('{{= foo("bar") }}', { foo:function(s){ return s; }}), 'bar' );
test_handler( "functions pass arguments correctly", R('{{= foo(bar) }}', { foo:function(s){ return s; }, 'bar':'baz'}), 'baz' );
var cls = {
toString:function () {return 'S';},
toValue:function () {return 'V';}
}
test_handler( 'variables use toString, not toValue', R("{{= foo }}",{foo:cls}), 'S' );
test_handler( 'comma passes variables correctly', R("{{= dot,dot,comma,dash }}",{dot:'.','comma':',','dash':'-'}), '-' );
// @borgar says: I don't like this: it should use foo() to be consistant with foo().bar()
test_handler( 'variable gets called if it is callable', R("{{= fun }}",O), 'RETURNED' );
test_handler( 'last variable in sequence gets called if it is callable', R("{{= obj.fun }}",{obj:O}), 'RETURNED' );
var cls = {
foo: function () {
return { bar: function () {return 'BAZ'; } };
}
}
test_handler( 'member functions in a sequence don\'t get called', R("{{= foo.bar }}", cls), '' );
// TODO: escaping
test_handler( 'echoing escapes html', R("{{= 'foo<div>bar</div>baz' }}"), 'foo&lt;div&gt;bar&lt;/div&gt;baz' );
test_handler( 'echoing escapes html (lookup)', R("{{= r }}", {r:'foo<div>bar</div>baz'}), 'foo&lt;div&gt;bar&lt;/div&gt;baz' );
test_handler( 'echoing escapes ampersands 1', R("{{= '&' }}"), '&amp;' );
test_handler( 'echoing escapes ampersands 2', R("{{= '&amp;' }}"), '&amp;amp;' );
test_handler( 'echoing escapes & < >', R("{{= '-<&>-<&>-' }}"), '-&lt;&amp;&gt;-&lt;&amp;&gt;-' );
});
test("Caching", function() {
// these tests are a bit awkward because caching is done in $.render, not $.tmpl
jQuery.templates['name'] = jQuery.tmpl( "<span>name: {{= v }}</span>" );
test_handler( "using a named template", $.render('name', O)[0].innerHTML, 'name: test' );
var $elm = $( "<span>name: {{= v }}</span>" );
$elm.render(O);
test_handler( "reusing a template cached in node data", $elm.data("tmpl").call(O, jQuery, O, 0), 'name: test' );
});
test("Tag: each", function() {
test_handler( "loop", R('{{each arr}}{{= $i }}:{{= this }}/{{/each}}', O), '0:AA/1:BB/2:CC/' );
test_handler( "loop", R('{{ each arr as i, item }}{{= i }}:{{= item }}/{{ /each }}', O), '0:AA/1:BB/2:CC/' );
test_handler( "loop", R('{{ each arr as i, item }}{{= i }}:{{= this }}/{{ /each }}', O), '0:AA/1:BB/2:CC/' );
test_handler( "loop", R('{{ each arr }}{{= $i }}:{{= this }}/{{ /each }}', O), '0:AA/1:BB/2:CC/' );
// values
test_handler( "loop over empty dict", R('{{ each dict }}{{=}} {{ /each }}', { dict: {} }), "");
test_handler( "loop over empty array", R('{{ each arr }}{{=}} {{ /each }}', { arr: [] }), "");
test_handler( "loop over string", R('{{ each one }}{{=}} {{ /each }}', O), "f i r s t ");
test_handler( "loop over undefined var (TypeError)", R('{{ each missing }}{{=}} {{ /each }}', O), TypeError);
test_handler( "loop over undefined value (TypeError)", R('{{ each dict.missing }}{{=}} {{ /each }}', O), TypeError);
test_handler( "loop over null (TypeError)", R('{{ each n }}{{=}} {{ /each }}', { n: null }), TypeError);
test_handler( "loop over integer primitive (TypeError)", R('{{ each count }}{{=}} {{ /each }}', { b: true }), TypeError);
test_handler( "loop over boolean primitive (TypeError)", R('{{ each b }}{{=}} {{ /each }}', O), TypeError);
test_handler( "first", R('{{ each dict }}{{= $i }}:{{ if $first }}first{{ else }}!first{{ /if }}/{{ /each }}', O), 'leovinus:first/scraliontis:!first/brobostigon:!first/' );
test_handler( "first", R('{{ each dict }}{{ if !$first }}, {{ /if }}{{= $i }}:{{ = this }}{{ /each }}', O), 'leovinus:this, scraliontis:that, brobostigon:other' );
var nested = '{{ each this as i,a }}{{ each a.b as j,b }}{{= i }}:{{= a.s }}/{{= j }}:{{= b.s }} {{ /each }}{{ /each }}';
test_handler( "nested loops", R(nested, [{s:"foo",b:[{s:"AA"},{s:"BB"}]},{s:"bar",b:[{s:"CC"},{s:"DD"}]}]), "0:foo/0:AA 0:foo/1:BB 1:bar/0:CC 1:bar/1:DD ");
test_handler( "callable", R('{{ each this }}{{= this.length }}{{ /each }}', function() { return ["one", "three", "five"]; }), "354");
test_handler( 'errors are passed back correctly (syntax)', R("{{each arr}}{{= $i }}{{ syntax_error }}{{/each}}",O), SyntaxError );
test_handler( 'errors are passed back correctly (reference)', R("{{each arr}}{{= $i }}{{ reference_error }}{{/each}}",O), ReferenceError );
test_handler( 'errors are passed back correctly (type)', R("{{each arr}}{{= $i }}{{ type_error }}{{/each}}",O), TypeError );
});
test("Tag: with", function() {
test_handler( "without name does nothing", R('{{ with one }}{{= one }}{{ /with }}', O), 'first' );
test_handler( "without name does nothing (2)", R('{{ with one }}{{= two }}{{ /with }}', O), 'second' );
test_handler( "new name non-destructively overrides any existing", R('{{ with "whee" as two }}{{= two }}{{ /with }}-{{= two }}', O), 'whee-second' );
test_handler( "operations on passed variable work", R('{{ with "123" + one + "456" as foo }}{{= foo }}{{ /with }}', O), '123first456' );
test_handler( "works with member lookups", R('{{ with a.b.c as foo }}{{= foo }}{{ /with }}', {a:{b:{c:"bar"}}}), 'bar' );
test_handler( "member lookups accept operations", R('{{ with (a.b.c + 5) as foo }}{{= foo + 2 }}{{ /with }}', {a:{b:{c:5}}}), '12' );
test_handler( "callable", R('{{ with this }}{{= this.length }}{{ /with }}', function() { return "foo"; }), "3");
test_handler( 'errors are passed back correctly (syntax)', R("{{with arr}}{{= $i }}{{ syntax_error }}{{/with}}",O), SyntaxError );
test_handler( 'errors are passed back correctly (reference)', R("{{with arr}}{{= $i }}{{ reference_error }}{{/with}}",O), ReferenceError );
test_handler( 'errors are passed back correctly (type)', R("{{with arr}}{{= $i }}{{ type_error }}{{/with}}",O), TypeError );
});
test("Tag: if", function() {
test_handler( "if with no parameters", R('{{ if }}TRUE{{ else }}FALSE{{ /if }}', { a:true }), SyntaxError );
test_handler( "if:true", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:true }), 'TRUE' );
test_handler( "if:false", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:false }), 'FALSE' );
test_handler( "if:null", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:null }), 'FALSE' );
test_handler( "if:undefined", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:undefined }), 'FALSE' );
test_handler( "if:[]", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:{} }), 'TRUE' );
test_handler( "if:{}", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:[] }), 'TRUE' );
test_handler( "if:''", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:"" }), 'FALSE' );
test_handler( "if:A", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:"A" }), 'TRUE' );
test_handler( "if:0", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:0 }), 'FALSE' );
test_handler( "if:1", R('{{ if a }}TRUE{{ else }}FALSE{{ /if }}', { a:1 }), 'TRUE' );
// functions are truthy, so this test is only useful if the function returns a falsy value
test_handler( "callable", R('{{ if this }}TRUE{{ else }}FALSE{{ /if }}', function() { return false; }), 'FALSE');
test_handler( "/if ignores following text", R('{{ if a }}TRUE{{ else }}FALSE{{ /if a }}', { a:1 }), 'TRUE' );
test_handler( 'errors are passed back correctly (syntax)', R("{{if true}}{{ syntax_error }}{{/if}}",O), SyntaxError );
test_handler( 'errors are passed back correctly (reference)', R("{{if true}}{{ reference_error }}{{/if}}",O), ReferenceError );
test_handler( 'errors are passed back correctly (type)', R("{{if true}}{{ type_error }}{{/if}}",O), TypeError );
});
test("Tag: include", function() {
jQuery.templates['test'] = jQuery.tmpl('{{= "test" }}');
test_handler( "simple include", R('{{ include "test" }}'), 'test' );
jQuery.templates['test2'] = jQuery.tmpl('{{ each arr as n,itm }}[{{= itm }}]-{{ /each }}');
test_handler( "data access", R('{{ include "test2" }}', O), '[AA]-[BB]-[CC]-' );
jQuery.templates['test3'] = jQuery.tmpl('{{=}}');
test_handler( "context (with)", R('{{= one }}/{{ with two }}{{ include "test3" }}{{ /with }}', O), 'first/second' );
test_handler( "context (each)", R('{{= one }}/{{ each arr }}{{ include "test3" }}-{{ /each }}', O), 'first/AA-BB-CC-' );
test_handler( "callable", R('{{ include this }}', function() { return "test"; }), "test");
test_handler( "nonexistent template (artificial ReferenceError)", R('{{ include "grobble" }}', O), ReferenceError );
});
test("Plugin: autocache", function() {
test_handler('template from "html script"', $.templates.Foo.call(O, jQuery, O), "foo-first");
test_handler("template from class name", $.templates.bar.call(O, jQuery, O), "bar-second");
});
</script>
</head>
<body>
<h1 id="qunit-header">jQuery-tmpl</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="template-bar" class="jquery-tmpl" style="display:none">bar-{{= two }}</div>
</body>
</html>