ractive
Version:
Next-generation DOM manipulation
1,230 lines (1,208 loc) • 33.2 kB
JavaScript
// MUSTACHE SPEC COMPLIANCE TESTS
// ==============================
//
// These are included to aid development; Ractive will never be able to pass
// every test in the suite because it's doing something fundamentally different
// to other mustache implementations.
//
// Unpassable tests are marked as such.
//
// Some tests technically fail in IE8. This is because IE8 is shit. The library
// works fine, but IE8 gets all confused about whitespace when doing innerHTML.
// For the sake of sanity, these tests are also marked.
define([ 'ractive' ], function ( Ractive ) {
return function () {
var fixture, testModules, runTest, runModule, i, isOldIe;
fixture = document.getElementById( 'qunit-fixture' );
testModules = [
{
name: 'Comments',
tests: [
{
name: "Inline",
data: {},
expected: "1234567890",
template: "12345{{! Comment Block! }}67890",
desc: "Comment blocks should be removed from the template."
},
{
name: "Multiline",
data: {},
expected: "1234567890\n",
template: "12345{{!\n This is a\n multi-line comment...\n}}67890\n",
desc: "Multiline comments should be permitted."
},
{
name: "Standalone",
data: {},
expected: "Begin.\nEnd.\n",
template: "Begin.\n{{! Comment Block! }}\nEnd.\n",
desc: "All standalone comment lines should be removed."
},
{
name: "Indented Standalone",
data: {},
expected: "Begin.\nEnd.\n",
template: "Begin.\n {{! Indented Comment Block! }}\nEnd.\n",
desc: "All standalone comment lines should be removed."
},
{
name: "Standalone Line Endings",
data: {},
expected: "|\r\n|",
template: "|\r\n{{! Standalone Comment }}\r\n|",
desc: "\"\\r\\n\" should be considered a newline for standalone tags."
},
{
name: "Standalone Without Previous Line",
data: {},
expected: "!",
template: " {{! I'm Still Standalone }}\n!",
desc: "Standalone tags should not require a newline to precede them."
},
{
name: "Standalone Without Newline",
data: {},
expected: "!\n",
template: "!\n {{! I'm Still Standalone }}",
desc: "Standalone tags should not require a newline to follow them."
},
{
name: "Multiline Standalone",
data: {},
expected: "Begin.\nEnd.\n",
template: "Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n",
desc: "All standalone comment lines should be removed."
},
{
name: "Indented Multiline Standalone",
data: {},
expected: "Begin.\nEnd.\n",
template: "Begin.\n {{!\n Something's going on here...\n }}\nEnd.\n",
desc: "All standalone comment lines should be removed."
},
{
name: "Indented Inline",
data: {},
expected: " 12 \n",
template: " 12 {{! 3 4 }}\n",
desc: "Inline comments should not strip whitespace"
},
{
name: "Surrounding Whitespace",
data: {},
expected: "12345 67890",
template: "12345 {{! Comment Block! }} 67890",
desc: "Comment removal should preserve surrounding whitespace."
}
]
},
{
name: 'Delimiters',
tests: [
{
name: "Pair Behavior",
data: {
text: "Hey!"
},
expected: "(Hey!)",
template: "{{=<% %>=}}(<%text%>)",
desc: "The equals sign (used on both sides) should permit delimiter changes."
},
{
name: "Special Characters",
data: {
text: "It worked!"
},
expected: "(It worked!)",
template: "({{=[ ]=}}[text])",
desc: "Characters with special meaning regexen should be valid delimiters."
},
{
name: "Sections",
data: {
section: true,
data: "I got interpolated."
},
expected: "[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n",
template: "[\n{{#section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|#section|\n {{data}}\n |data|\n|/section|\n]\n",
desc: "Delimiters set outside sections should persist.",
oldIe: true
},
{
name: "Inverted Sections",
data: {
section: false,
data: "I got interpolated."
},
expected: "[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n",
template: "[\n{{^section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|^section|\n {{data}}\n |data|\n|/section|\n]\n",
desc: "Delimiters set outside inverted sections should persist.",
oldIe: true
},
{
name: "Partial Inheritence",
data: {
value: "yes"
},
expected: "[ .yes. ]\n[ .yes. ]\n",
template: "[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n",
desc: "Delimiters set in a parent template should not affect a partial.",
partials: {
include: ".{{value}}."
},
oldIe: true
},
{
name: "Post-Partial Behavior",
data: {
value: "yes"
},
expected: "[ .yes. .yes. ]\n[ .yes. .|value|. ]\n",
template: "[ {{>include}} ]\n[ .{{value}}. .|value|. ]\n",
desc: "Delimiters set in a partial should not affect the parent template.",
partials: {
// Note: the original test looked like this:
// include: ".{{value}}. {{= | | =}} .|value|."
// This breaks in Ractive because the | is assumed to be part of the
// expression
include: ".{{value}}. {{= <% %> =}} .<%value%>."
},
oldIe: true
},
{
name: "Surrounding Whitespace",
data: {},
expected: "| |",
template: "| {{=@ @=}} |",
desc: "Surrounding whitespace should be left untouched."
},
{
name: "Outlying Whitespace (Inline)",
data: {},
expected: " | \n",
template: " | {{=@ @=}}\n",
desc: "Whitespace should be left untouched."
},
{
name: "Standalone Tag",
data: {},
expected: "Begin.\nEnd.\n",
template: "Begin.\n{{=@ @=}}\nEnd.\n",
desc: "Standalone lines should be removed from the template."
},
{
name: "Indented Standalone Tag",
data: {},
expected: "Begin.\nEnd.\n",
template: "Begin.\n {{=@ @=}}\nEnd.\n",
desc: "Indented standalone lines should be removed from the template."
},
{
name: "Standalone Line Endings",
data: {},
expected: "|\r\n|",
template: "|\r\n{{= @ @ =}}\r\n|",
desc: "\"\\r\\n\" should be considered a newline for standalone tags."
},
{
name: "Standalone Without Previous Line",
data: {},
expected: "=",
template: " {{=@ @=}}\n=",
desc: "Standalone tags should not require a newline to precede them."
},
{
name: "Standalone Without Newline",
data: {},
expected: "=\n",
template: "=\n {{=@ @=}}",
desc: "Standalone tags should not require a newline to follow them."
},
{
name: "Pair with Padding",
data: {},
expected: "||",
template: "|{{= @ @ =}}|",
desc: "Superfluous in-tag whitespace should be ignored."
}
]
},
{
name: 'Interpolation',
tests: [
{
name: "No Interpolation",
data: {},
expected: "Hello from {Mustache}!\n",
template: "Hello from {Mustache}!\n",
desc: "Mustache-free templates should render as-is."
},
{
name: "Basic Interpolation",
data: {
subject: "world"
},
expected: "Hello, world!\n",
template: "Hello, {{subject}}!\n",
desc: "Unadorned tags should interpolate content into the template."
},
{
name: "HTML Escaping",
data: {
forbidden: "& \" < >"
},
expected: "These characters should be HTML escaped: & " < >\n",
template: "These characters should be HTML escaped: {{forbidden}}\n",
desc: "Basic interpolation should be HTML escaped."
},
{
name: "Triple Mustache",
data: {
forbidden: "& \" < >"
},
expected: "These characters should not be HTML escaped: & \" < >\n",
template: "These characters should not be HTML escaped: {{{forbidden}}}\n",
desc: "Triple mustaches should interpolate without HTML escaping."
},
{
name: "Ampersand",
data: {
forbidden: "& \" < >"
},
expected: "These characters should not be HTML escaped: & \" < >\n",
template: "These characters should not be HTML escaped: {{&forbidden}}\n",
desc: "Ampersand should interpolate without HTML escaping."
},
{
name: "Basic Integer Interpolation",
data: {
mph: 85
},
expected: "\"85 miles an hour!\"",
template: "\"{{mph}} miles an hour!\"",
desc: "Integers should interpolate seamlessly."
},
{
name: "Triple Mustache Integer Interpolation",
data: {
mph: 85
},
expected: "\"85 miles an hour!\"",
template: "\"{{{mph}}} miles an hour!\"",
desc: "Integers should interpolate seamlessly."
},
{
name: "Ampersand Integer Interpolation",
data: {
mph: 85
},
expected: "\"85 miles an hour!\"",
template: "\"{{&mph}} miles an hour!\"",
desc: "Integers should interpolate seamlessly."
},
{
name: "Basic Decimal Interpolation",
data: {
power: 1.21
},
expected: "\"1.21 jiggawatts!\"",
template: "\"{{power}} jiggawatts!\"",
desc: "Decimals should interpolate seamlessly with proper significance."
},
{
name: "Triple Mustache Decimal Interpolation",
data: {
power: 1.21
},
expected: "\"1.21 jiggawatts!\"",
template: "\"{{{power}}} jiggawatts!\"",
desc: "Decimals should interpolate seamlessly with proper significance."
},
{
name: "Ampersand Decimal Interpolation",
data: {
power: 1.21
},
expected: "\"1.21 jiggawatts!\"",
template: "\"{{&power}} jiggawatts!\"",
desc: "Decimals should interpolate seamlessly with proper significance."
},
{
name: "Basic Context Miss Interpolation",
data: {},
expected: "I () be seen!",
template: "I ({{cannot}}) be seen!",
desc: "Failed context lookups should default to empty strings."
},
{
name: "Triple Mustache Context Miss Interpolation",
data: {},
expected: "I () be seen!",
template: "I ({{{cannot}}}) be seen!",
desc: "Failed context lookups should default to empty strings."
},
{
name: "Ampersand Context Miss Interpolation",
data: {},
expected: "I () be seen!",
template: "I ({{&cannot}}) be seen!",
desc: "Failed context lookups should default to empty strings."
},
{
name: "Dotted Names - Basic Interpolation",
data: {
person: {
name: "Joe"
}
},
expected: "\"Joe\" == \"Joe\"",
template: "\"{{person.name}}\" == \"{{#person}}{{name}}{{/person}}\"",
desc: "Dotted names should be considered a form of shorthand for sections."
},
{
name: "Dotted Names - Triple Mustache Interpolation",
data: {
person: {
name: "Joe"
}
},
expected: "\"Joe\" == \"Joe\"",
template: "\"{{{person.name}}}\" == \"{{#person}}{{{name}}}{{/person}}\"",
desc: "Dotted names should be considered a form of shorthand for sections."
},
{
name: "Dotted Names - Ampersand Interpolation",
data: {
person: {
name: "Joe"
}
},
expected: "\"Joe\" == \"Joe\"",
template: "\"{{&person.name}}\" == \"{{#person}}{{&name}}{{/person}}\"",
desc: "Dotted names should be considered a form of shorthand for sections."
},
{
name: "Dotted Names - Arbitrary Depth",
data: {
a: {
b: {
c: {
d: {
e: {
name: "Phil"
}
}
}
}
}
},
expected: "\"Phil\" == \"Phil\"",
template: "\"{{a.b.c.d.e.name}}\" == \"Phil\"",
desc: "Dotted names should be functional to any level of nesting."
},
{
name: "Dotted Names - Broken Chains",
data: {
a: {}
},
expected: "\"\" == \"\"",
template: "\"{{a.b.c}}\" == \"\"",
desc: "Any falsey value prior to the last part of the name should yield ''."
},
{
name: "Dotted Names - Broken Chain Resolution",
data: {
a: {
b: {}
},
c: {
name: "Jim"
}
},
expected: "\"\" == \"\"",
template: "\"{{a.b.c.name}}\" == \"\"",
desc: "Each part of a dotted name should resolve only against its parent."
},
{
name: "Dotted Names - Initial Resolution",
data: {
a: {
b: {
c: {
d: {
e: {
name: "Phil"
}
}
}
}
},
b: {
c: {
d: {
e: {
name: "Wrong"
}
}
}
}
},
expected: "\"Phil\" == \"Phil\"",
template: "\"{{#a}}{{b.c.d.e.name}}{{/a}}\" == \"Phil\"",
desc: "The first part of a dotted name should resolve as any other name."
},
{
name: "Interpolation - Surrounding Whitespace",
data: {
string: "---"
},
expected: "| --- |",
template: "| {{string}} |",
desc: "Interpolation should not alter surrounding whitespace."
},
{
name: "Triple Mustache - Surrounding Whitespace",
data: {
string: "---"
},
expected: "| --- |",
template: "| {{{string}}} |",
desc: "Interpolation should not alter surrounding whitespace."
},
{
name: "Ampersand - Surrounding Whitespace",
data: {
string: "---"
},
expected: "| --- |",
template: "| {{&string}} |",
desc: "Interpolation should not alter surrounding whitespace."
},
{
name: "Interpolation - Standalone",
data: {
string: "---"
},
expected: " ---\n",
template: " {{string}}\n",
desc: "Standalone interpolation should not alter surrounding whitespace."
},
{
name: "Triple Mustache - Standalone",
data: {
string: "---"
},
expected: " ---\n",
template: " {{{string}}}\n",
desc: "Standalone interpolation should not alter surrounding whitespace."
},
{
name: "Ampersand - Standalone",
data: {
string: "---"
},
expected: " ---\n",
template: " {{&string}}\n",
desc: "Standalone interpolation should not alter surrounding whitespace."
},
{
name: "Interpolation With Padding",
data: {
string: "---"
},
expected: "|---|",
template: "|{{ string }}|",
desc: "Superfluous in-tag whitespace should be ignored."
},
{
name: "Triple Mustache With Padding",
data: {
string: "---"
},
expected: "|---|",
template: "|{{{ string }}}|",
desc: "Superfluous in-tag whitespace should be ignored."
},
{
name: "Ampersand With Padding",
data: {
string: "---"
},
expected: "|---|",
template: "|{{& string }}|",
desc: "Superfluous in-tag whitespace should be ignored."
}
]
},
{
name: 'Inverted',
tests: [
{
name: "Falsey",
data: {
boolean: false
},
expected: "\"This should be rendered.\"",
template: "\"{{^boolean}}This should be rendered.{{/boolean}}\"",
desc: "Falsey sections should have their contents rendered."
},
{
name: "Truthy",
data: {
boolean: true
},
expected: "\"\"",
template: "\"{{^boolean}}This should not be rendered.{{/boolean}}\"",
desc: "Truthy sections should have their contents omitted."
},
{
name: "Context",
data: {
context: {
name: "Joe"
}
},
expected: "\"\"",
template: "\"{{^context}}Hi {{name}}.{{/context}}\"",
desc: "Objects and hashes should behave like truthy values."
},
{
name: "List",
data: {
list: [
{
n: 1
},
{
n: 2
},
{
n: 3
}
]
},
expected: "\"\"",
template: "\"{{^list}}{{n}}{{/list}}\"",
desc: "Lists should behave like truthy values."
},
{
name: "Empty List",
data: {
list: []
},
expected: "\"Yay lists!\"",
template: "\"{{^list}}Yay lists!{{/list}}\"",
desc: "Empty lists should behave like falsey values."
},
{
name: "Doubled",
data: {
two: "second",
bool: false
},
expected: "* first\n* second\n* third\n",
template: "{{^bool}}\n* first\n{{/bool}}\n* {{two}}\n{{^bool}}\n* third\n{{/bool}}\n",
desc: "Multiple inverted sections per template should be permitted.",
oldIe: true
},
{
name: "Nested (Falsey)",
data: {
bool: false
},
expected: "| A B C D E |",
template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |",
desc: "Nested falsey sections should have their contents rendered."
},
{
name: "Nested (Truthy)",
data: {
bool: true
},
expected: "| A E |",
template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |",
desc: "Nested truthy sections should be omitted."
},
{
name: "Context Misses",
data: {},
expected: "[Cannot find key 'missing'!]",
template: "[{{^missing}}Cannot find key 'missing'!{{/missing}}]",
desc: "Failed context lookups should be considered falsey."
},
{
name: "Dotted Names - Truthy",
data: {
a: {
b: {
c: true
}
}
},
expected: "\"\" == \"\"",
template: "\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"\"",
desc: "Dotted names should be valid for Inverted Section tags."
},
{
name: "Dotted Names - Falsey",
data: {
a: {
b: {
c: false
}
}
},
expected: "\"Not Here\" == \"Not Here\"",
template: "\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\"",
desc: "Dotted names should be valid for Inverted Section tags."
},
{
name: "Dotted Names - Broken Chains",
data: {
a: {}
},
expected: "\"Not Here\" == \"Not Here\"",
template: "\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\"",
desc: "Dotted names that cannot be resolved should be considered falsey."
},
{
name: "Surrounding Whitespace",
data: {
boolean: false
},
expected: " | \t|\t | \n",
template: " | {{^boolean}}\t|\t{{/boolean}} | \n",
desc: "Inverted sections should not alter surrounding whitespace."
},
{
name: "Internal Whitespace",
data: {
boolean: false
},
expected: " | \n | \n",
template: " | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n",
desc: "Inverted should not alter internal whitespace."
},
{
name: "Indented Inline Sections",
data: {
boolean: false
},
expected: " NO\n WAY\n",
template: " {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n",
desc: "Single-line sections should not alter surrounding whitespace."
},
{
name: "Standalone Lines",
data: {
boolean: false
},
expected: "| This Is\n|\n| A Line\n",
template: "| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n",
desc: "Standalone lines should be removed from the template.",
oldIe: true
},
{
name: "Standalone Indented Lines",
data: {
boolean: false
},
expected: "| This Is\n|\n| A Line\n",
template: "| This Is\n {{^boolean}}\n|\n {{/boolean}}\n| A Line\n",
desc: "Standalone indented lines should be removed from the template.",
oldIe: true
},
{
name: "Standalone Line Endings",
data: {
boolean: false
},
expected: "|\r\n|",
template: "|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|",
desc: "\"\\r\\n\" should be considered a newline for standalone tags.",
unpassable: true
},
{
name: "Standalone Without Previous Line",
data: {
boolean: false
},
expected: "^\n/",
template: " {{^boolean}}\n^{{/boolean}}\n/",
desc: "Standalone tags should not require a newline to precede them.",
oldIe: true
},
{
name: "Standalone Without Newline",
data: {
boolean: false
},
expected: "^\n/\n",
template: "^{{^boolean}}\n/\n {{/boolean}}",
desc: "Standalone tags should not require a newline to follow them.",
oldIe: true
},
{
name: "Padding",
data: {
boolean: false
},
expected: "|=|",
template: "|{{^ boolean }}={{/ boolean }}|",
desc: "Superfluous in-tag whitespace should be ignored."
}
]
},
{
name: 'Partials',
tests: [
{
name: "Basic Behavior",
data: {},
expected: "\"from partial\"",
template: "\"{{>text}}\"",
desc: "The greater-than operator should expand to the named partial.",
partials: {
text: "from partial"
}
},
{
name: "Failed Lookup",
data: {},
expected: "\"\"",
template: "\"{{>text}}\"",
desc: "The empty string should be used when the named partial is not found.",
partials: {}
},
{
name: "Context",
data: {
text: "content"
},
expected: "\"*content*\"",
template: "\"{{>partial}}\"",
desc: "The greater-than operator should operate within the current context.",
partials: {
partial: "*{{text}}*"
}
},
{
name: "Recursion",
data: {
content: "X",
nodes: [
{
content: "Y",
nodes: []
}
]
},
expected: "X(Y())",
template: "{{>node}}",
desc: "The greater-than operator should properly recurse.",
partials: {
node: "{{content}}({{#nodes}}{{>node}}{{/nodes}})"
}
},
{
name: "Surrounding Whitespace",
data: {},
expected: "| \t|\t |",
template: "| {{>partial}} |",
desc: "The greater-than operator should not alter surrounding whitespace.",
partials: {
partial: "\t|\t"
}
},
{
name: "Inline Indentation",
data: {
data: "|"
},
expected: " | >\n>\n",
template: " {{data}} {{> partial}}\n",
desc: "Whitespace should be left untouched.",
partials: {
partial: ">\n>"
}
},
{
name: "Standalone Line Endings",
data: {},
expected: "|\r\n>|",
template: "|\r\n{{>partial}}\r\n|",
desc: "\"\\r\\n\" should be considered a newline for standalone tags.",
partials: {
partial: ">"
},
oldIe: true,
unpassable: true
},
{
name: "Standalone Without Previous Line",
data: {},
expected: " >\n >>",
template: " {{>partial}}\n>",
desc: "Standalone tags should not require a newline to precede them.",
partials: {
partial: ">\n>"
},
unpassable: true
},
{
name: "Standalone Without Newline",
data: {},
expected: ">\n >\n >",
template: ">\n {{>partial}}",
desc: "Standalone tags should not require a newline to follow them.",
partials: {
partial: ">\n>"
},
unpassable: true
},
{
name: "Standalone Indentation",
data: {
content: "<\n->"
},
expected: "\\\n |\n <\n->\n |\n/\n",
template: "\\\n {{>partial}}\n/\n",
desc: "Each line of the partial should be indented before rendering.",
partials: {
partial: "|\n{{{content}}}\n|\n"
},
unpassable: true
},
{
name: "Padding Whitespace",
data: {
boolean: true
},
expected: "|[]|",
template: "|{{> partial }}|",
desc: "Superfluous in-tag whitespace should be ignored.",
partials: {
partial: "[]"
}
}
]
},
{
name: 'Sections',
tests: [
{
name: "Truthy",
data: {
boolean: true
},
expected: "\"This should be rendered.\"",
template: "\"{{#boolean}}This should be rendered.{{/boolean}}\"",
desc: "Truthy sections should have their contents rendered."
},
{
name: "Falsey",
data: {
boolean: false
},
expected: "\"\"",
template: "\"{{#boolean}}This should not be rendered.{{/boolean}}\"",
desc: "Falsey sections should have their contents omitted."
},
{
name: "Context",
data: {
context: {
name: "Joe"
}
},
expected: "\"Hi Joe.\"",
template: "\"{{#context}}Hi {{name}}.{{/context}}\"",
desc: "Objects and hashes should be pushed onto the context stack."
},
{
name: "Deeply Nested Contexts",
data: {
a: {
one: 1
},
b: {
two: 2
},
c: {
three: 3
},
d: {
four: 4
},
e: {
five: 5
}
},
expected: "1\n121\n12321\n1234321\n123454321\n1234321\n12321\n121\n1\n",
template: "{{#a}}\n{{one}}\n{{#b}}\n{{one}}{{two}}{{one}}\n{{#c}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{#d}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{#e}}\n{{one}}{{two}}{{three}}{{four}}{{five}}{{four}}{{three}}{{two}}{{one}}\n{{/e}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{/d}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{/c}}\n{{one}}{{two}}{{one}}\n{{/b}}\n{{one}}\n{{/a}}\n",
desc: "All elements on the context stack should be accessible.",
oldIe: true
},
{
name: "List",
data: {
list: [
{
item: 1
},
{
item: 2
},
{
item: 3
}
]
},
expected: "\"123\"",
template: "\"{{#list}}{{item}}{{/list}}\"",
desc: "Lists should be iterated; list items should visit the context stack."
},
{
name: "Empty List",
data: {
list: []
},
expected: "\"\"",
template: "\"{{#list}}Yay lists!{{/list}}\"",
desc: "Empty lists should behave like falsey values."
},
{
name: "Doubled",
data: {
two: "second",
bool: true
},
expected: "* first\n* second\n* third\n",
template: "{{#bool}}\n* first\n{{/bool}}\n* {{two}}\n{{#bool}}\n* third\n{{/bool}}\n",
desc: "Multiple sections per template should be permitted.",
oldIe: true
},
{
name: "Nested (Truthy)",
data: {
bool: true
},
expected: "| A B C D E |",
template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |",
desc: "Nested truthy sections should have their contents rendered."
},
{
name: "Nested (Falsey)",
data: {
bool: false
},
expected: "| A E |",
template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |",
desc: "Nested falsey sections should be omitted."
},
{
name: "Context Misses",
data: {},
expected: "[]",
template: "[{{#missing}}Found key 'missing'!{{/missing}}]",
desc: "Failed context lookups should be considered falsey."
},
{
name: "Implicit Iterator - String",
data: {
list: [
"a",
"b",
"c",
"d",
"e"
]
},
expected: "\"(a)(b)(c)(d)(e)\"",
template: "\"{{#list}}({{.}}){{/list}}\"",
desc: "Implicit iterators should directly interpolate strings."
},
{
name: "Implicit Iterator - Integer",
data: {
list: [
1,
2,
3,
4,
5
]
},
expected: "\"(1)(2)(3)(4)(5)\"",
template: "\"{{#list}}({{.}}){{/list}}\"",
desc: "Implicit iterators should cast integers to strings and interpolate."
},
{
name: "Implicit Iterator - Decimal",
data: {
list: [
1.1,
2.2,
3.3,
4.4,
5.5
]
},
expected: "\"(1.1)(2.2)(3.3)(4.4)(5.5)\"",
template: "\"{{#list}}({{.}}){{/list}}\"",
desc: "Implicit iterators should cast decimals to strings and interpolate."
},
{
name: "Dotted Names - Truthy",
data: {
a: {
b: {
c: true
}
}
},
expected: "\"Here\" == \"Here\"",
template: "\"{{#a.b.c}}Here{{/a.b.c}}\" == \"Here\"",
desc: "Dotted names should be valid for Section tags."
},
{
name: "Dotted Names - Falsey",
data: {
a: {
b: {
c: false
}
}
},
expected: "\"\" == \"\"",
template: "\"{{#a.b.c}}Here{{/a.b.c}}\" == \"\"",
desc: "Dotted names should be valid for Section tags."
},
{
name: "Dotted Names - Broken Chains",
data: {
a: {}
},
expected: "\"\" == \"\"",
template: "\"{{#a.b.c}}Here{{/a.b.c}}\" == \"\"",
desc: "Dotted names that cannot be resolved should be considered falsey."
},
{
name: "Surrounding Whitespace",
data: {
boolean: true
},
expected: " | \t|\t | \n",
template: " | {{#boolean}}\t|\t{{/boolean}} | \n",
desc: "Sections should not alter surrounding whitespace."
},
{
name: "Internal Whitespace",
data: {
boolean: true
},
expected: " | \n | \n",
template: " | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n",
desc: "Sections should not alter internal whitespace."
},
{
name: "Indented Inline Sections",
data: {
boolean: true
},
expected: " YES\n GOOD\n",
template: " {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n",
desc: "Single-line sections should not alter surrounding whitespace."
},
{
name: "Standalone Lines",
data: {
boolean: true
},
expected: "| This Is\n|\n| A Line\n",
template: "| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n",
desc: "Standalone lines should be removed from the template.",
oldIe: true
},
{
name: "Indented Standalone Lines",
data: {
boolean: true
},
expected: "| This Is\n|\n| A Line\n",
template: "| This Is\n {{#boolean}}\n|\n {{/boolean}}\n| A Line\n",
desc: "Indented standalone lines should be removed from the template.",
oldIe: true
},
{
name: "Standalone Line Endings",
data: {
boolean: true
},
expected: "|\r\n|",
template: "|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|",
desc: "\"\\r\\n\" should be considered a newline for standalone tags.",
unpassable: true
},
{
name: "Standalone Without Previous Line",
data: {
boolean: true
},
expected: "#\n/",
template: " {{#boolean}}\n#{{/boolean}}\n/",
desc: "Standalone tags should not require a newline to precede them.",
oldIe: true
},
{
name: "Standalone Without Newline",
data: {
boolean: true
},
expected: ":\n/\n",
template: ":{{#boolean}}\n/\n {{/boolean}}",
desc: "Standalone tags should not require a newline to follow them.",
oldIe: true
},
{
name: "Padding",
data: {
boolean: true
},
expected: "|=|",
template: "|{{# boolean }}={{/ boolean }}|",
desc: "Superfluous in-tag whitespace should be ignored."
}
]
}
];
isOldIe = /MSIE [6-8]/.test( navigator.userAgent );
runTest = function ( theTest ) {
test( theTest.name, function ( t ) {
var ractive;
ractive = new Ractive({
el: fixture,
template: theTest.template,
data: theTest.data,
partials: theTest.partials,
preserveWhitespace: true
});
t.htmlEqual( fixture.innerHTML, theTest.expected, theTest.desc + '\n' + theTest.template + '\n' );
});
};
runModule = function ( theModule ) {
var i, theTest;
module( 'Mustache compliance (' + theModule.name + ')' );
for ( i=0; i<theModule.tests.length; i+=1 ) {
theTest = theModule.tests[i];
if ( !theTest.unpassable && ( !isOldIe || !theTest.oldIe ) ) {
runTest( theModule.tests[i] );
}
}
};
for ( i=0; i<testModules.length; i+=1 ) {
runModule( testModules[i] );
}
};
});