This is a conformance suite for the draft jQuery template language.
Each row in the tables below is a test case.
The "test" column includes the literal text of a template wrapped in
an <xmp>
element.
The "data" column includes a data value as JavaScript text also
wrapped in an <xmp>
.
The "expected" column shows the expected output of the template when compiled and applied to the data. If the output starts with "Error:" then the compilation or application should fail with an exception, and in debug mode should produce the following error message.
The "actual" column is auto-generated and contains the actual result and is colored to indicate success or failure.
The right-most column, if any, includes explatory text about the test-case.
Any "test" cells whose content consists of named templates specified via
<script type="text/x-jquery-tmpl" id="template-name">
elements will have all templates extracted and compiled as a bundle
and the template with id="main"
will be the one applied.
To test the reference implementation, add
?reference
to the URL.
To test the reference implementation, add
?compressed
to the URL.
To run just some tests, add ?testFilter=<RegExp>
where <RegExp>
matches the right-most column, the
test description.
To turn off logging to the console, add ?nolog
to the URL.
The tests below test the built-in operators, and plugins that ship by default.
Test | Data | Expected | Actual | |||||||
---|---|---|---|---|---|---|---|---|---|---|
Empty Template | ||||||||||
Hello, World! | Plain text | |||||||||
Hello, <World>! | HTML entities preserved | |||||||||
𐀀 | 𐀀 | Supplemental codepoints preserved | ||||||||
- | - | Orphaned surrogates preserved | ||||||||
foo bar | Newlines preserved. | |||||||||
a b${'\u2029'}c | a b c | Unusual newlines | ||||||||
Hello, World! | HTML tags preserved | |||||||||
It costs $5, 5$. {if} {{/- {{. | Dollars and curlies in text | |||||||||
Cow says mfoo, dog says bark | Substitution | |||||||||
Cow says mfoo, dog says bark | Substitution unabbreviated syntax | |||||||||
Error:world is not defined | Substitution w/out data | |||||||||
i=42, f=0.5, nf=-0.5, nan=NaN, inf=Infinity, nzero=0 | Substitution numbers | |||||||||
s=Hello, World!, n=42, nul=, supp=𐀀 | Substitution strings | |||||||||
orphans=- | Substitution non-unicode strings | |||||||||
t=true, f=false | Substitution booleans | |||||||||
s=foo, o=[Obj], thunk=Hello, World!, a=1,2,3 | Substitution objects | |||||||||
Hello, string! | toString vs valueOf | |||||||||
i++=0, i++=1, readOnce=42, counter=1, counter=2 | Substitution evaluation happens once and in order | |||||||||
${breaker} |
-->]]></script></style></textarea>" ' ) > |
Substitution autoescaped | ||||||||
Hello, Cincinatti! | If branch taken | |||||||||
Goodbye, Cleveland! | Else branch taken | |||||||||
Hello, Cincinatti! | If branch taken no else | |||||||||
, Cleveland! | No else branch | |||||||||
Goodbye, Cincinatti! | Condition in else taken | |||||||||
, Cincinatti! | Condition in else not taken | |||||||||
Hello, Cincinatti! | If branch taken based on truthy value | |||||||||
Goodbye, Cleveland! | Else branch taken based on falsey value | |||||||||
|
|
Loop over array | ||||||||
|
Loop over empty | |||||||||
|
|
Loop with custom key variable name | ||||||||
|
|
Loop with custom variable names | ||||||||
|
|
Loop over associative array. | ||||||||
this x=x, that x=(x) | Template Calls | |||||||||
Error:Invalid {{tmpl}} content: ({ x, y }) "that" | Invalid Template Param | |||||||||
Error:Invalid {{tmpl}} content: ({ x: y }) "that | Invalid Template Selector | |||||||||
this x=x, that x=(y) | Call with different data | |||||||||
this x=1, that x=(3) | Template Order of Evaluation | |||||||||
11 | String concatenation of adjacent subs | |||||||||
2 | Arithmetic in substitution | |||||||||
a[0].b[cStr]=42 | Member expressions | |||||||||
undef= | Undefined member | |||||||||
-... | Recursive template | |||||||||
none | Unreached variable need not be defined | |||||||||
Error:Unclosed block directives if in {{if cond}}foo{{else}} | Missing {{/if}} error message | |||||||||
Error:{{else}} without condition must be last:{{if cond}}foo{{else}}bar{{else}}boo{{/if}} | Misplaced {{else}} | |||||||||
Error:{{if}} missing condition:{{if }}foo{{/if}} | Missing {{if}} condition | |||||||||
Error:I do not know how to compile {{unknown}} | Unknown directive name | |||||||||
Error:Invalid template substitution: i + (j | Catch obviously broken expressions early. | |||||||||
Error:Invalid template substitution: String()) } { (String() | Unbracketing and rebracketing illegal. | |||||||||
42 | "arguments" as a data key | |||||||||
Error:arguments is not defined | "arguments" not present as a data key | |||||||||
Error:arguments is not defined | "arguments" really not present as a data key | |||||||||
42, 42 | "arguments" really not present as a data key | |||||||||
42 | Template options available | |||||||||
option,data,option | Data masking template options | |||||||||
option,option2,option | Passing options |
The table below shows the template language extended with a few plugins.
{{makeID varName}}
assigns an ID using a
counter and puts it in the variable named varName
.
The Date format plugin annotates all substitutions to convert any
Date
instances into a prescribed format without
introducing new syntax.
The import plugin looks for a call to a template named
notYetLoaded
and if so, adds a template to the parse tree
bundle that outputs "Loaded just in time!"
Test | Data | Expected | Actual | |
---|---|---|---|---|
|
{{makeID}} plugin | |||
Error:I do not know how to compile {{makeid listItemId}} | directive names case-sensitive | |||
Date: 2007-01-15, a number: 2010 | Format date plugin | |||
Main calls and Loaded just in time! | Import plugin |
Tests migrated from the original implementation.
The global testData
is set to
lorem ipsum | plain text passes through untouched | |||
---|---|---|---|---|
first | simple variable output | |||
multi word variable tag | ||||
Error: _ is not defined | _ (underscore) cannot be used by data | |||
Error: $ overridden | $ cannot be used by data | |||
Error:I do not know how to compile {{syntax_error }} | sytax error passing | |||
Error:I do not know how to compile {{type_error }} | type error passing | |||
Error:I do not know how to compile {{reference_error }} | reference error passing | |||
first | newlines do not kill tags | |||
${ one } | first | carriage returns do notkill tags | ||
on e | returns in strings don't kill tags | |||
on\e | slashes in strings don't kill tags | |||
a b c8. | newlines don't kill parsing | |||
{{}} | default | |||
{{ }} | with whitespace | |||
{{ }} | with tabs whitespace | |||
Error:Unclosed block directives if in {{if 1}}{{if 1}}{{/if}} | default | |||
Error:Misplaced {{/if}} in {{if 1}}{{/if}}{{/if}} | extra /if | |||
Error:Misplaced {{/if}} in {{if 1}}{{each arr}}{{/if}}{{/each}} | but terminated | |||
a {{one } b | ignore malformed a {{one } b | |||
first} {{second} | ignore malformed first} {{second } | |||
{{one } | ignore malformed {{one } | |||
Disallow function operator | ||||
Disallow return | ||||
Disallow for | ||||
Disallow do/while | ||||
Disallow do/while 2 | ||||
Disallow if | ||||
Disallow try/catch | ||||
Disallow with keyword | ||||
Disallow throw keyword | ||||
baz | bracketed accessor foo["bar"] | |||
baz | bracketed accessor foo['bar'] | |||
bar baz' } |
foo<div>bar</div>baz | echoing escapes html | ||
bar baz'} |
foo<div>bar</div>baz | echoing escapes html (lookup) | ||
& | echoing escapes ampersands 1 | |||
& | echoing escapes ampersands 2 | |||
-<&>-<&>- | echoing escapes & < > | |||
AB | comments are removed | |||
foo | comments are removed (2) | |||
AB | comments may include string of comments | |||
AD #}B | comments cannot nest other comments | |||
AB | comments may include strings with escapes (double) | |||
AB | comments may include strings with escapes (single) | |||
AB | comments may include tags | |||
AB | comments may span lines | |||
A{{else}}B | comments split tokens 1 | |||
A{{else}}B | comments split tokens 2 | |||
{# not a comment } | no comments in markers | |||
12 | comments may contain invalid content (invalid tag) | |||
12 | comments may contain invalid content (stray end tag) | |||
12 | comments may contain invalid content (stray else) | |||
12 | comments may contain invalid content (invalid javascript) | |||
first | variable replacement | |||
first/second | many variables work | |||
first | alternative variable syntax | |||
first/second | many variables work with alt syntax | |||
string | basic string output (double) | |||
string | basic string output (single) | |||
str"i"ng | string quote escapes (double) | |||
str'i'ng | string quote escapes (single) | |||
{{ tag }} | string output with tag | |||
}} | string output with end of tag | |||
self | empty variable tag (with tabs whitespace) | |||
self | empty variable tag | |||
self | empty variable tag (with space) | |||
variable lookup error suppression | ||||
variable lookup error suppression (with member) | ||||
Afirst | variable and text (1) | |||
firstB | variable and text (2) | |||
AfirstB | variable and text (3) | |||
abc | lookups work for submembers | |||
abc | error suppression works for submembers | |||
bar | functions can be called with in tags | |||
bar | functions pass strings correctly | |||
baz | functions pass arguments correctly | |||
S | variables use toString, not toValue | |||
- | comma passes variables correctly | |||
RETURNED | variable gets called if it is callable | |||
RETURNED | last variable in sequence gets called if it is callable | |||
member functions in a sequence don't get called | ||||
0 | (0) | |||
false | (false) | |||
null | (null) | |||
(undefined) | ||||
("") | ||||
('') | ||||
0 | (false) | |||
false | (false) | |||
null | (null) | |||
(undefined) | ||||
('') | ||||
firstfoo | string concatenation | |||
6 | adding | |||
4 | subtracting | |||
1 | modulo | |||
-10 | unary minus | |||
10 | unary plus | |||
true | in operator | |||
true | instanceof operator | |||
string | typeof operator | |||
1 | bitwise AND | |||
5 | bitwise OR | |||
4 | bitwise XOR | |||
-6 | bitwise NOT | |||
10 | left shift | |||
2 | right shift | |||
2 | zero-fill right shift | |||
false | comparing == | |||
true | comparing != | |||
true | comparing === | |||
false | comparing !== | |||
false | comparing >= | |||
false | comparing > | |||
true | comparing <= | |||
true | comparing < | |||
FALSY | Logical OR | |||
TRUEY | Logical AND | |||
zero | Conditional Operator | |||
false | Unary logical NOT | |||
test | Single-Quoted Strings | |||
true | Single-Quoted Comparison | |||
Error: | Disallow incremental assignment | |||
Error: | Disallow decremental assignment | |||
Error: | Disallow multiply assignment | |||
Error: | Disallow division assignment | |||
Error: | Disallow left shift assignment | |||
Error: | Disallow right shift assignment | |||
Error: | Disallow zero-fill right shift assignment | |||
Error: | Disallow bitwise AND assignment | |||
Error: | Disallow bitwise OR assignment | |||
Error: | Disallow bitwise XOR assignment | |||
Error: | Disallow literal object creation | |||
Error: | Disallow literal array creation | |||
Error: | Disallow decrement | |||
Error: | Disallow assignments | |||
0:AA/1:BB/2:CC/ | loop | |||
0:AA/1:BB/2:CC/ | loop | |||
0:AA/1:BB/2:CC/ | loop | |||
0:AA/1:BB/2:CC/ | loop | |||
leovinus:first/scraliontis:!first/brobostigon:!first/ | first | |||
leovinus:this, scraliontis:that, brobostigon:other | first | |||
012 | html content | |||
AABBCC | html content | |||
012 | html content | |||
0 1 2 | html content with newlines | |||
Error:I do not know how to compile {{syntax_error}} | errors are passed back correctly (syntax) | |||
Error:I do not know how to compile {{reference_error}} | errors are passed back correctly (reference) | |||
Error:I do not know how to compile {{type_error}} | errors are passed back correctly (type) | |||
TRUE | if:true | |||
FALSE | if:false | |||
FALSE | if:null | |||
FALSE | if:undefined | |||
TRUE | if:[] | |||
TRUE | if:{} | |||
FALSE | if:'' | |||
TRUE | if:A | |||
FALSE | if:0 | |||
TRUE | if:1 | |||
TRUE | /if ignores following text | |||
Error:I do not know how to compile {{syntax_error}} | errors are passed back correctly (syntax) | |||
Error:I do not know how to compile {{reference_error}} | errors are passed back correctly (reference) | |||
Error:I do not know how to compile {{type_error}} | errors are passed back correctly (type) | |||
test text | simple include | |||
[AA]-[BB]-[CC]- | data access | |||
bar | nested - 1 level | |||
bar | nested - 2 levels | |||
1 | nested - 2 levels - complex data | |||
012 | {{each}} index variable | |||
012 | {{each}} index variable | |||
AABBCC | {{each}} item variable | |||
<a> | encoded | |||
unencoded |