refator: In spec tests, use expectTemplate over equals and shouldThrow (#1683)
This commit is contained in:
+387
-399
@@ -6,117 +6,156 @@ beforeEach(function() {
|
||||
|
||||
describe('basic context', function() {
|
||||
it('most basic', function() {
|
||||
shouldCompileTo('{{foo}}', { foo: 'foo' }, 'foo');
|
||||
expectTemplate('{{foo}}')
|
||||
.withInput({ foo: 'foo' })
|
||||
.toCompileTo('foo');
|
||||
});
|
||||
|
||||
it('escaping', function() {
|
||||
shouldCompileTo('\\{{foo}}', { foo: 'food' }, '{{foo}}');
|
||||
shouldCompileTo('content \\{{foo}}', { foo: 'food' }, 'content {{foo}}');
|
||||
shouldCompileTo('\\\\{{foo}}', { foo: 'food' }, '\\food');
|
||||
shouldCompileTo('content \\\\{{foo}}', { foo: 'food' }, 'content \\food');
|
||||
shouldCompileTo('\\\\ {{foo}}', { foo: 'food' }, '\\\\ food');
|
||||
expectTemplate('\\{{foo}}')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('{{foo}}');
|
||||
|
||||
expectTemplate('content \\{{foo}}')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('content {{foo}}');
|
||||
|
||||
expectTemplate('\\\\{{foo}}')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('\\food');
|
||||
|
||||
expectTemplate('content \\\\{{foo}}')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('content \\food');
|
||||
|
||||
expectTemplate('\\\\ {{foo}}')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('\\\\ food');
|
||||
});
|
||||
|
||||
it('compiling with a basic context', function() {
|
||||
shouldCompileTo(
|
||||
'Goodbye\n{{cruel}}\n{{world}}!',
|
||||
{ cruel: 'cruel', world: 'world' },
|
||||
'Goodbye\ncruel\nworld!',
|
||||
'It works if all the required keys are provided'
|
||||
);
|
||||
expectTemplate('Goodbye\n{{cruel}}\n{{world}}!')
|
||||
.withInput({
|
||||
cruel: 'cruel',
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('It works if all the required keys are provided')
|
||||
.toCompileTo('Goodbye\ncruel\nworld!');
|
||||
});
|
||||
|
||||
it('compiling with a string context', function() {
|
||||
shouldCompileTo('{{.}}{{length}}', 'bye', 'bye3');
|
||||
expectTemplate('{{.}}{{length}}')
|
||||
.withInput('bye')
|
||||
.toCompileTo('bye3');
|
||||
});
|
||||
|
||||
it('compiling with an undefined context', function() {
|
||||
shouldCompileTo(
|
||||
'Goodbye\n{{cruel}}\n{{world.bar}}!',
|
||||
undefined,
|
||||
'Goodbye\n\n!'
|
||||
);
|
||||
expectTemplate('Goodbye\n{{cruel}}\n{{world.bar}}!')
|
||||
.withInput(undefined)
|
||||
.toCompileTo('Goodbye\n\n!');
|
||||
|
||||
shouldCompileTo(
|
||||
'{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}',
|
||||
undefined,
|
||||
'Goodbye'
|
||||
);
|
||||
expectTemplate('{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}')
|
||||
.withInput(undefined)
|
||||
.toCompileTo('Goodbye');
|
||||
});
|
||||
|
||||
it('comments', function() {
|
||||
shouldCompileTo(
|
||||
'{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!',
|
||||
{ cruel: 'cruel', world: 'world' },
|
||||
'Goodbye\ncruel\nworld!',
|
||||
'comments are ignored'
|
||||
expectTemplate('{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!')
|
||||
.withInput({
|
||||
cruel: 'cruel',
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('comments are ignored')
|
||||
.toCompileTo('Goodbye\ncruel\nworld!');
|
||||
|
||||
expectTemplate(' {{~! comment ~}} blah').toCompileTo('blah');
|
||||
|
||||
expectTemplate(' {{~!-- long-comment --~}} blah').toCompileTo(
|
||||
'blah'
|
||||
);
|
||||
|
||||
shouldCompileTo(' {{~! comment ~}} blah', {}, 'blah');
|
||||
shouldCompileTo(' {{~!-- long-comment --~}} blah', {}, 'blah');
|
||||
shouldCompileTo(' {{! comment ~}} blah', {}, ' blah');
|
||||
shouldCompileTo(' {{!-- long-comment --~}} blah', {}, ' blah');
|
||||
shouldCompileTo(' {{~! comment}} blah', {}, ' blah');
|
||||
shouldCompileTo(' {{~!-- long-comment --}} blah', {}, ' blah');
|
||||
expectTemplate(' {{! comment ~}} blah').toCompileTo(' blah');
|
||||
|
||||
expectTemplate(' {{!-- long-comment --~}} blah').toCompileTo(
|
||||
' blah'
|
||||
);
|
||||
|
||||
expectTemplate(' {{~! comment}} blah').toCompileTo(' blah');
|
||||
|
||||
expectTemplate(' {{~!-- long-comment --}} blah').toCompileTo(
|
||||
' blah'
|
||||
);
|
||||
});
|
||||
|
||||
it('boolean', function() {
|
||||
var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!';
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{ goodbye: true, world: 'world' },
|
||||
'GOODBYE cruel world!',
|
||||
'booleans show the contents when true'
|
||||
);
|
||||
expectTemplate(string)
|
||||
.withInput({
|
||||
goodbye: true,
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('booleans show the contents when true')
|
||||
.toCompileTo('GOODBYE cruel world!');
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{ goodbye: false, world: 'world' },
|
||||
'cruel world!',
|
||||
'booleans do not show the contents when false'
|
||||
);
|
||||
expectTemplate(string)
|
||||
.withInput({
|
||||
goodbye: false,
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('booleans do not show the contents when false')
|
||||
.toCompileTo('cruel world!');
|
||||
});
|
||||
|
||||
it('zeros', function() {
|
||||
shouldCompileTo(
|
||||
'num1: {{num1}}, num2: {{num2}}',
|
||||
{ num1: 42, num2: 0 },
|
||||
'num1: 42, num2: 0'
|
||||
);
|
||||
shouldCompileTo('num: {{.}}', 0, 'num: 0');
|
||||
shouldCompileTo('num: {{num1/num2}}', { num1: { num2: 0 } }, 'num: 0');
|
||||
expectTemplate('num1: {{num1}}, num2: {{num2}}')
|
||||
.withInput({
|
||||
num1: 42,
|
||||
num2: 0
|
||||
})
|
||||
.toCompileTo('num1: 42, num2: 0');
|
||||
|
||||
expectTemplate('num: {{.}}')
|
||||
.withInput(0)
|
||||
.toCompileTo('num: 0');
|
||||
|
||||
expectTemplate('num: {{num1/num2}}')
|
||||
.withInput({ num1: { num2: 0 } })
|
||||
.toCompileTo('num: 0');
|
||||
});
|
||||
|
||||
it('false', function() {
|
||||
/* eslint-disable no-new-wrappers */
|
||||
shouldCompileTo(
|
||||
'val1: {{val1}}, val2: {{val2}}',
|
||||
{ val1: false, val2: new Boolean(false) },
|
||||
'val1: false, val2: false'
|
||||
);
|
||||
shouldCompileTo('val: {{.}}', false, 'val: false');
|
||||
shouldCompileTo(
|
||||
'val: {{val1/val2}}',
|
||||
{ val1: { val2: false } },
|
||||
'val: false'
|
||||
);
|
||||
expectTemplate('val1: {{val1}}, val2: {{val2}}')
|
||||
.withInput({
|
||||
val1: false,
|
||||
val2: new Boolean(false)
|
||||
})
|
||||
.toCompileTo('val1: false, val2: false');
|
||||
|
||||
shouldCompileTo(
|
||||
'val1: {{{val1}}}, val2: {{{val2}}}',
|
||||
{ val1: false, val2: new Boolean(false) },
|
||||
'val1: false, val2: false'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'val: {{{val1/val2}}}',
|
||||
{ val1: { val2: false } },
|
||||
'val: false'
|
||||
);
|
||||
expectTemplate('val: {{.}}')
|
||||
.withInput(false)
|
||||
.toCompileTo('val: false');
|
||||
|
||||
expectTemplate('val: {{val1/val2}}')
|
||||
.withInput({ val1: { val2: false } })
|
||||
.toCompileTo('val: false');
|
||||
|
||||
expectTemplate('val1: {{{val1}}}, val2: {{{val2}}}')
|
||||
.withInput({
|
||||
val1: false,
|
||||
val2: new Boolean(false)
|
||||
})
|
||||
.toCompileTo('val1: false, val2: false');
|
||||
|
||||
expectTemplate('val: {{{val1/val2}}}')
|
||||
.withInput({ val1: { val2: false } })
|
||||
.toCompileTo('val: false');
|
||||
/* eslint-enable */
|
||||
});
|
||||
|
||||
it('should handle undefined and null', function() {
|
||||
shouldCompileTo(
|
||||
'{{awesome undefined null}}',
|
||||
{
|
||||
expectTemplate('{{awesome undefined null}}')
|
||||
.withInput({
|
||||
awesome: function(_undefined, _null, options) {
|
||||
return (
|
||||
(_undefined === undefined) +
|
||||
@@ -126,373 +165,325 @@ describe('basic context', function() {
|
||||
typeof options
|
||||
);
|
||||
}
|
||||
},
|
||||
'true true object'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{undefined}}',
|
||||
{
|
||||
})
|
||||
.toCompileTo('true true object');
|
||||
|
||||
expectTemplate('{{undefined}}')
|
||||
.withInput({
|
||||
undefined: function() {
|
||||
return 'undefined!';
|
||||
}
|
||||
},
|
||||
'undefined!'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{null}}',
|
||||
{
|
||||
})
|
||||
.toCompileTo('undefined!');
|
||||
|
||||
expectTemplate('{{null}}')
|
||||
.withInput({
|
||||
null: function() {
|
||||
return 'null!';
|
||||
}
|
||||
},
|
||||
'null!'
|
||||
);
|
||||
})
|
||||
.toCompileTo('null!');
|
||||
});
|
||||
|
||||
it('newlines', function() {
|
||||
shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest");
|
||||
shouldCompileTo("Alan's\rTest", {}, "Alan's\rTest");
|
||||
expectTemplate("Alan's\nTest").toCompileTo("Alan's\nTest");
|
||||
|
||||
expectTemplate("Alan's\rTest").toCompileTo("Alan's\rTest");
|
||||
});
|
||||
|
||||
it('escaping text', function() {
|
||||
shouldCompileTo(
|
||||
"Awesome's",
|
||||
{},
|
||||
"Awesome's",
|
||||
"text is escaped so that it doesn't get caught on single quotes"
|
||||
);
|
||||
shouldCompileTo(
|
||||
'Awesome\\',
|
||||
{},
|
||||
'Awesome\\',
|
||||
"text is escaped so that the closing quote can't be ignored"
|
||||
);
|
||||
shouldCompileTo(
|
||||
'Awesome\\\\ foo',
|
||||
{},
|
||||
'Awesome\\\\ foo',
|
||||
"text is escaped so that it doesn't mess up backslashes"
|
||||
);
|
||||
shouldCompileTo(
|
||||
'Awesome {{foo}}',
|
||||
{ foo: '\\' },
|
||||
'Awesome \\',
|
||||
"text is escaped so that it doesn't mess up backslashes"
|
||||
);
|
||||
shouldCompileTo(
|
||||
" ' ' ",
|
||||
{},
|
||||
" ' ' ",
|
||||
'double quotes never produce invalid javascript'
|
||||
);
|
||||
expectTemplate("Awesome's")
|
||||
.withMessage(
|
||||
"text is escaped so that it doesn't get caught on single quotes"
|
||||
)
|
||||
.toCompileTo("Awesome's");
|
||||
|
||||
expectTemplate('Awesome\\')
|
||||
.withMessage("text is escaped so that the closing quote can't be ignored")
|
||||
.toCompileTo('Awesome\\');
|
||||
|
||||
expectTemplate('Awesome\\\\ foo')
|
||||
.withMessage("text is escaped so that it doesn't mess up backslashes")
|
||||
.toCompileTo('Awesome\\\\ foo');
|
||||
|
||||
expectTemplate('Awesome {{foo}}')
|
||||
.withInput({ foo: '\\' })
|
||||
.withMessage("text is escaped so that it doesn't mess up backslashes")
|
||||
.toCompileTo('Awesome \\');
|
||||
|
||||
expectTemplate(" ' ' ")
|
||||
.withMessage('double quotes never produce invalid javascript')
|
||||
.toCompileTo(" ' ' ");
|
||||
});
|
||||
|
||||
it('escaping expressions', function() {
|
||||
shouldCompileTo(
|
||||
'{{{awesome}}}',
|
||||
{ awesome: "&'\\<>" },
|
||||
"&'\\<>",
|
||||
"expressions with 3 handlebars aren't escaped"
|
||||
);
|
||||
expectTemplate('{{{awesome}}}')
|
||||
.withInput({ awesome: "&'\\<>" })
|
||||
.withMessage("expressions with 3 handlebars aren't escaped")
|
||||
.toCompileTo("&'\\<>");
|
||||
|
||||
shouldCompileTo(
|
||||
'{{&awesome}}',
|
||||
{ awesome: "&'\\<>" },
|
||||
"&'\\<>",
|
||||
"expressions with {{& handlebars aren't escaped"
|
||||
);
|
||||
expectTemplate('{{&awesome}}')
|
||||
.withInput({ awesome: "&'\\<>" })
|
||||
.withMessage("expressions with {{& handlebars aren't escaped")
|
||||
.toCompileTo("&'\\<>");
|
||||
|
||||
shouldCompileTo(
|
||||
'{{awesome}}',
|
||||
{ awesome: '&"\'`\\<>' },
|
||||
'&"'`\\<>',
|
||||
'by default expressions should be escaped'
|
||||
);
|
||||
expectTemplate('{{awesome}}')
|
||||
.withInput({ awesome: '&"\'`\\<>' })
|
||||
.withMessage('by default expressions should be escaped')
|
||||
.toCompileTo('&"'`\\<>');
|
||||
|
||||
shouldCompileTo(
|
||||
'{{awesome}}',
|
||||
{ awesome: 'Escaped, <b> looks like: <b>' },
|
||||
'Escaped, <b> looks like: &lt;b&gt;',
|
||||
'escaping should properly handle amperstands'
|
||||
);
|
||||
expectTemplate('{{awesome}}')
|
||||
.withInput({ awesome: 'Escaped, <b> looks like: <b>' })
|
||||
.withMessage('escaping should properly handle amperstands')
|
||||
.toCompileTo('Escaped, <b> looks like: &lt;b&gt;');
|
||||
});
|
||||
|
||||
it("functions returning safestrings shouldn't be escaped", function() {
|
||||
var hash = {
|
||||
awesome: function() {
|
||||
return new Handlebars.SafeString("&'\\<>");
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{awesome}}',
|
||||
hash,
|
||||
"&'\\<>",
|
||||
"functions returning safestrings aren't escaped"
|
||||
);
|
||||
expectTemplate('{{awesome}}')
|
||||
.withInput({
|
||||
awesome: function() {
|
||||
return new Handlebars.SafeString("&'\\<>");
|
||||
}
|
||||
})
|
||||
.withMessage("functions returning safestrings aren't escaped")
|
||||
.toCompileTo("&'\\<>");
|
||||
});
|
||||
|
||||
it('functions', function() {
|
||||
shouldCompileTo(
|
||||
'{{awesome}}',
|
||||
{
|
||||
expectTemplate('{{awesome}}')
|
||||
.withInput({
|
||||
awesome: function() {
|
||||
return 'Awesome';
|
||||
}
|
||||
},
|
||||
'Awesome',
|
||||
'functions are called and render their output'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{awesome}}',
|
||||
{
|
||||
})
|
||||
.withMessage('functions are called and render their output')
|
||||
.toCompileTo('Awesome');
|
||||
|
||||
expectTemplate('{{awesome}}')
|
||||
.withInput({
|
||||
awesome: function() {
|
||||
return this.more;
|
||||
},
|
||||
more: 'More awesome'
|
||||
},
|
||||
'More awesome',
|
||||
'functions are bound to the context'
|
||||
);
|
||||
})
|
||||
.withMessage('functions are bound to the context')
|
||||
.toCompileTo('More awesome');
|
||||
});
|
||||
|
||||
it('functions with context argument', function() {
|
||||
shouldCompileTo(
|
||||
'{{awesome frank}}',
|
||||
{
|
||||
expectTemplate('{{awesome frank}}')
|
||||
.withInput({
|
||||
awesome: function(context) {
|
||||
return context;
|
||||
},
|
||||
frank: 'Frank'
|
||||
},
|
||||
'Frank',
|
||||
'functions are called with context arguments'
|
||||
);
|
||||
})
|
||||
.withMessage('functions are called with context arguments')
|
||||
.toCompileTo('Frank');
|
||||
});
|
||||
|
||||
it('pathed functions with context argument', function() {
|
||||
shouldCompileTo(
|
||||
'{{bar.awesome frank}}',
|
||||
{
|
||||
expectTemplate('{{bar.awesome frank}}')
|
||||
.withInput({
|
||||
bar: {
|
||||
awesome: function(context) {
|
||||
return context;
|
||||
}
|
||||
},
|
||||
frank: 'Frank'
|
||||
},
|
||||
'Frank',
|
||||
'functions are called with context arguments'
|
||||
);
|
||||
})
|
||||
.withMessage('functions are called with context arguments')
|
||||
.toCompileTo('Frank');
|
||||
});
|
||||
|
||||
it('depthed functions with context argument', function() {
|
||||
shouldCompileTo(
|
||||
'{{#with frank}}{{../awesome .}}{{/with}}',
|
||||
{
|
||||
expectTemplate('{{#with frank}}{{../awesome .}}{{/with}}')
|
||||
.withInput({
|
||||
awesome: function(context) {
|
||||
return context;
|
||||
},
|
||||
frank: 'Frank'
|
||||
},
|
||||
'Frank',
|
||||
'functions are called with context arguments'
|
||||
);
|
||||
})
|
||||
.withMessage('functions are called with context arguments')
|
||||
.toCompileTo('Frank');
|
||||
});
|
||||
|
||||
it('block functions with context argument', function() {
|
||||
shouldCompileTo(
|
||||
'{{#awesome 1}}inner {{.}}{{/awesome}}',
|
||||
{
|
||||
expectTemplate('{{#awesome 1}}inner {{.}}{{/awesome}}')
|
||||
.withInput({
|
||||
awesome: function(context, options) {
|
||||
return options.fn(context);
|
||||
}
|
||||
},
|
||||
'inner 1',
|
||||
'block functions are called with context and options'
|
||||
);
|
||||
})
|
||||
.withMessage('block functions are called with context and options')
|
||||
.toCompileTo('inner 1');
|
||||
});
|
||||
|
||||
it('depthed block functions with context argument', function() {
|
||||
shouldCompileTo(
|
||||
'{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}',
|
||||
{
|
||||
expectTemplate(
|
||||
'{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}'
|
||||
)
|
||||
.withInput({
|
||||
value: true,
|
||||
awesome: function(context, options) {
|
||||
return options.fn(context);
|
||||
}
|
||||
},
|
||||
'inner 1',
|
||||
'block functions are called with context and options'
|
||||
);
|
||||
})
|
||||
.withMessage('block functions are called with context and options')
|
||||
.toCompileTo('inner 1');
|
||||
});
|
||||
|
||||
it('block functions without context argument', function() {
|
||||
shouldCompileTo(
|
||||
'{{#awesome}}inner{{/awesome}}',
|
||||
{
|
||||
expectTemplate('{{#awesome}}inner{{/awesome}}')
|
||||
.withInput({
|
||||
awesome: function(options) {
|
||||
return options.fn(this);
|
||||
}
|
||||
},
|
||||
'inner',
|
||||
'block functions are called with options'
|
||||
);
|
||||
})
|
||||
.withMessage('block functions are called with options')
|
||||
.toCompileTo('inner');
|
||||
});
|
||||
|
||||
it('pathed block functions without context argument', function() {
|
||||
shouldCompileTo(
|
||||
'{{#foo.awesome}}inner{{/foo.awesome}}',
|
||||
{
|
||||
expectTemplate('{{#foo.awesome}}inner{{/foo.awesome}}')
|
||||
.withInput({
|
||||
foo: {
|
||||
awesome: function() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
},
|
||||
'inner',
|
||||
'block functions are called with options'
|
||||
);
|
||||
})
|
||||
.withMessage('block functions are called with options')
|
||||
.toCompileTo('inner');
|
||||
});
|
||||
|
||||
it('depthed block functions without context argument', function() {
|
||||
shouldCompileTo(
|
||||
'{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}',
|
||||
{
|
||||
expectTemplate(
|
||||
'{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}'
|
||||
)
|
||||
.withInput({
|
||||
value: true,
|
||||
awesome: function() {
|
||||
return this;
|
||||
}
|
||||
},
|
||||
'inner',
|
||||
'block functions are called with options'
|
||||
);
|
||||
})
|
||||
.withMessage('block functions are called with options')
|
||||
.toCompileTo('inner');
|
||||
});
|
||||
|
||||
it('paths with hyphens', function() {
|
||||
shouldCompileTo(
|
||||
'{{foo-bar}}',
|
||||
{ 'foo-bar': 'baz' },
|
||||
'baz',
|
||||
'Paths can contain hyphens (-)'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{foo.foo-bar}}',
|
||||
{ foo: { 'foo-bar': 'baz' } },
|
||||
'baz',
|
||||
'Paths can contain hyphens (-)'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{foo/foo-bar}}',
|
||||
{ foo: { 'foo-bar': 'baz' } },
|
||||
'baz',
|
||||
'Paths can contain hyphens (-)'
|
||||
);
|
||||
expectTemplate('{{foo-bar}}')
|
||||
.withInput({ 'foo-bar': 'baz' })
|
||||
.withMessage('Paths can contain hyphens (-)')
|
||||
.toCompileTo('baz');
|
||||
|
||||
expectTemplate('{{foo.foo-bar}}')
|
||||
.withInput({ foo: { 'foo-bar': 'baz' } })
|
||||
.withMessage('Paths can contain hyphens (-)')
|
||||
.toCompileTo('baz');
|
||||
|
||||
expectTemplate('{{foo/foo-bar}}')
|
||||
.withInput({ foo: { 'foo-bar': 'baz' } })
|
||||
.withMessage('Paths can contain hyphens (-)')
|
||||
.toCompileTo('baz');
|
||||
});
|
||||
|
||||
it('nested paths', function() {
|
||||
shouldCompileTo(
|
||||
'Goodbye {{alan/expression}} world!',
|
||||
{ alan: { expression: 'beautiful' } },
|
||||
'Goodbye beautiful world!',
|
||||
'Nested paths access nested objects'
|
||||
);
|
||||
expectTemplate('Goodbye {{alan/expression}} world!')
|
||||
.withInput({ alan: { expression: 'beautiful' } })
|
||||
.withMessage('Nested paths access nested objects')
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
});
|
||||
|
||||
it('nested paths with empty string value', function() {
|
||||
shouldCompileTo(
|
||||
'Goodbye {{alan/expression}} world!',
|
||||
{ alan: { expression: '' } },
|
||||
'Goodbye world!',
|
||||
'Nested paths access nested objects with empty string'
|
||||
);
|
||||
expectTemplate('Goodbye {{alan/expression}} world!')
|
||||
.withInput({ alan: { expression: '' } })
|
||||
.withMessage('Nested paths access nested objects with empty string')
|
||||
.toCompileTo('Goodbye world!');
|
||||
});
|
||||
|
||||
it('literal paths', function() {
|
||||
shouldCompileTo(
|
||||
'Goodbye {{[@alan]/expression}} world!',
|
||||
{ '@alan': { expression: 'beautiful' } },
|
||||
'Goodbye beautiful world!',
|
||||
'Literal paths can be used'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'Goodbye {{[foo bar]/expression}} world!',
|
||||
{ 'foo bar': { expression: 'beautiful' } },
|
||||
'Goodbye beautiful world!',
|
||||
'Literal paths can be used'
|
||||
);
|
||||
expectTemplate('Goodbye {{[@alan]/expression}} world!')
|
||||
.withInput({ '@alan': { expression: 'beautiful' } })
|
||||
.withMessage('Literal paths can be used')
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
|
||||
expectTemplate('Goodbye {{[foo bar]/expression}} world!')
|
||||
.withInput({ 'foo bar': { expression: 'beautiful' } })
|
||||
.withMessage('Literal paths can be used')
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
});
|
||||
|
||||
it('literal references', function() {
|
||||
shouldCompileTo(
|
||||
'Goodbye {{[foo bar]}} world!',
|
||||
{ 'foo bar': 'beautiful' },
|
||||
'Goodbye beautiful world!'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'Goodbye {{"foo bar"}} world!',
|
||||
{ 'foo bar': 'beautiful' },
|
||||
'Goodbye beautiful world!'
|
||||
);
|
||||
shouldCompileTo(
|
||||
"Goodbye {{'foo bar'}} world!",
|
||||
{ 'foo bar': 'beautiful' },
|
||||
'Goodbye beautiful world!'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'Goodbye {{"foo[bar"}} world!',
|
||||
{ 'foo[bar': 'beautiful' },
|
||||
'Goodbye beautiful world!'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'Goodbye {{"foo\'bar"}} world!',
|
||||
{ "foo'bar": 'beautiful' },
|
||||
'Goodbye beautiful world!'
|
||||
);
|
||||
shouldCompileTo(
|
||||
"Goodbye {{'foo\"bar'}} world!",
|
||||
{ 'foo"bar': 'beautiful' },
|
||||
'Goodbye beautiful world!'
|
||||
);
|
||||
expectTemplate('Goodbye {{[foo bar]}} world!')
|
||||
.withInput({ 'foo bar': 'beautiful' })
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
|
||||
expectTemplate('Goodbye {{"foo bar"}} world!')
|
||||
.withInput({ 'foo bar': 'beautiful' })
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
|
||||
expectTemplate("Goodbye {{'foo bar'}} world!")
|
||||
.withInput({ 'foo bar': 'beautiful' })
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
|
||||
expectTemplate('Goodbye {{"foo[bar"}} world!')
|
||||
.withInput({ 'foo[bar': 'beautiful' })
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
|
||||
expectTemplate('Goodbye {{"foo\'bar"}} world!')
|
||||
.withInput({ "foo'bar": 'beautiful' })
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
|
||||
expectTemplate("Goodbye {{'foo\"bar'}} world!")
|
||||
.withInput({ 'foo"bar': 'beautiful' })
|
||||
.toCompileTo('Goodbye beautiful world!');
|
||||
});
|
||||
|
||||
it("that current context path ({{.}}) doesn't hit helpers", function() {
|
||||
shouldCompileTo('test: {{.}}', [null, { helper: 'awesome' }], 'test: ');
|
||||
expectTemplate('test: {{.}}')
|
||||
.withInput(null)
|
||||
.withHelpers({ helper: 'awesome' })
|
||||
.toCompileTo('test: ');
|
||||
});
|
||||
|
||||
it('complex but empty paths', function() {
|
||||
shouldCompileTo('{{person/name}}', { person: { name: null } }, '');
|
||||
shouldCompileTo('{{person/name}}', { person: {} }, '');
|
||||
expectTemplate('{{person/name}}')
|
||||
.withInput({ person: { name: null } })
|
||||
.toCompileTo('');
|
||||
|
||||
expectTemplate('{{person/name}}')
|
||||
.withInput({ person: {} })
|
||||
.toCompileTo('');
|
||||
});
|
||||
|
||||
it('this keyword in paths', function() {
|
||||
var string = '{{#goodbyes}}{{this}}{{/goodbyes}}';
|
||||
var hash = { goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] };
|
||||
shouldCompileTo(
|
||||
string,
|
||||
hash,
|
||||
'goodbyeGoodbyeGOODBYE',
|
||||
'This keyword in paths evaluates to current context'
|
||||
);
|
||||
expectTemplate('{{#goodbyes}}{{this}}{{/goodbyes}}')
|
||||
.withInput({ goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] })
|
||||
.withMessage('This keyword in paths evaluates to current context')
|
||||
.toCompileTo('goodbyeGoodbyeGOODBYE');
|
||||
|
||||
string = '{{#hellos}}{{this/text}}{{/hellos}}';
|
||||
hash = {
|
||||
hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }]
|
||||
};
|
||||
shouldCompileTo(
|
||||
string,
|
||||
hash,
|
||||
'helloHelloHELLO',
|
||||
'This keyword evaluates in more complex paths'
|
||||
);
|
||||
expectTemplate('{{#hellos}}{{this/text}}{{/hellos}}')
|
||||
.withInput({
|
||||
hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }]
|
||||
})
|
||||
.withMessage('This keyword evaluates in more complex paths')
|
||||
.toCompileTo('helloHelloHELLO');
|
||||
});
|
||||
|
||||
it('this keyword nested inside path', function() {
|
||||
shouldThrow(
|
||||
function() {
|
||||
CompilerContext.compile('{{#hellos}}{{text/this/foo}}{{/hellos}}');
|
||||
},
|
||||
expectTemplate('{{#hellos}}{{text/this/foo}}{{/hellos}}').toThrow(
|
||||
Error,
|
||||
'Invalid path: text/this - 1:13'
|
||||
);
|
||||
|
||||
shouldCompileTo('{{[this]}}', { this: 'bar' }, 'bar');
|
||||
shouldCompileTo('{{text/[this]}}', { text: { this: 'bar' } }, 'bar');
|
||||
expectTemplate('{{[this]}}')
|
||||
.withInput({ this: 'bar' })
|
||||
.toCompileTo('bar');
|
||||
|
||||
expectTemplate('{{text/[this]}}')
|
||||
.withInput({ text: { this: 'bar' } })
|
||||
.toCompileTo('bar');
|
||||
});
|
||||
|
||||
it('this keyword in helpers', function() {
|
||||
@@ -501,108 +492,105 @@ describe('basic context', function() {
|
||||
return 'bar ' + value;
|
||||
}
|
||||
};
|
||||
var string = '{{#goodbyes}}{{foo this}}{{/goodbyes}}';
|
||||
var hash = { goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] };
|
||||
shouldCompileTo(
|
||||
string,
|
||||
[hash, helpers],
|
||||
'bar goodbyebar Goodbyebar GOODBYE',
|
||||
'This keyword in paths evaluates to current context'
|
||||
);
|
||||
|
||||
string = '{{#hellos}}{{foo this/text}}{{/hellos}}';
|
||||
hash = {
|
||||
hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }]
|
||||
};
|
||||
shouldCompileTo(
|
||||
string,
|
||||
[hash, helpers],
|
||||
'bar hellobar Hellobar HELLO',
|
||||
'This keyword evaluates in more complex paths'
|
||||
);
|
||||
expectTemplate('{{#goodbyes}}{{foo this}}{{/goodbyes}}')
|
||||
.withInput({ goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] })
|
||||
.withHelpers(helpers)
|
||||
.withMessage('This keyword in paths evaluates to current context')
|
||||
.toCompileTo('bar goodbyebar Goodbyebar GOODBYE');
|
||||
|
||||
expectTemplate('{{#hellos}}{{foo this/text}}{{/hellos}}')
|
||||
.withInput({
|
||||
hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }]
|
||||
})
|
||||
.withHelpers(helpers)
|
||||
.withMessage('This keyword evaluates in more complex paths')
|
||||
.toCompileTo('bar hellobar Hellobar HELLO');
|
||||
});
|
||||
|
||||
it('this keyword nested inside helpers param', function() {
|
||||
var string = '{{#hellos}}{{foo text/this/foo}}{{/hellos}}';
|
||||
shouldThrow(
|
||||
function() {
|
||||
CompilerContext.compile(string);
|
||||
},
|
||||
expectTemplate('{{#hellos}}{{foo text/this/foo}}{{/hellos}}').toThrow(
|
||||
Error,
|
||||
'Invalid path: text/this - 1:17'
|
||||
);
|
||||
|
||||
shouldCompileTo(
|
||||
'{{foo [this]}}',
|
||||
{
|
||||
expectTemplate('{{foo [this]}}')
|
||||
.withInput({
|
||||
foo: function(value) {
|
||||
return value;
|
||||
},
|
||||
this: 'bar'
|
||||
},
|
||||
'bar'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{foo text/[this]}}',
|
||||
{
|
||||
})
|
||||
.toCompileTo('bar');
|
||||
|
||||
expectTemplate('{{foo text/[this]}}')
|
||||
.withInput({
|
||||
foo: function(value) {
|
||||
return value;
|
||||
},
|
||||
text: { this: 'bar' }
|
||||
},
|
||||
'bar'
|
||||
);
|
||||
})
|
||||
.toCompileTo('bar');
|
||||
});
|
||||
|
||||
it('pass string literals', function() {
|
||||
shouldCompileTo('{{"foo"}}', {}, '');
|
||||
shouldCompileTo('{{"foo"}}', { foo: 'bar' }, 'bar');
|
||||
shouldCompileTo(
|
||||
'{{#"foo"}}{{.}}{{/"foo"}}',
|
||||
{ foo: ['bar', 'baz'] },
|
||||
'barbaz'
|
||||
);
|
||||
expectTemplate('{{"foo"}}').toCompileTo('');
|
||||
|
||||
expectTemplate('{{"foo"}}')
|
||||
.withInput({ foo: 'bar' })
|
||||
.toCompileTo('bar');
|
||||
|
||||
expectTemplate('{{#"foo"}}{{.}}{{/"foo"}}')
|
||||
.withInput({
|
||||
foo: ['bar', 'baz']
|
||||
})
|
||||
.toCompileTo('barbaz');
|
||||
});
|
||||
|
||||
it('pass number literals', function() {
|
||||
shouldCompileTo('{{12}}', {}, '');
|
||||
shouldCompileTo('{{12}}', { '12': 'bar' }, 'bar');
|
||||
shouldCompileTo('{{12.34}}', {}, '');
|
||||
shouldCompileTo('{{12.34}}', { '12.34': 'bar' }, 'bar');
|
||||
shouldCompileTo(
|
||||
'{{12.34 1}}',
|
||||
{
|
||||
expectTemplate('{{12}}').toCompileTo('');
|
||||
|
||||
expectTemplate('{{12}}')
|
||||
.withInput({ '12': 'bar' })
|
||||
.toCompileTo('bar');
|
||||
|
||||
expectTemplate('{{12.34}}').toCompileTo('');
|
||||
|
||||
expectTemplate('{{12.34}}')
|
||||
.withInput({ '12.34': 'bar' })
|
||||
.toCompileTo('bar');
|
||||
|
||||
expectTemplate('{{12.34 1}}')
|
||||
.withInput({
|
||||
'12.34': function(arg) {
|
||||
return 'bar' + arg;
|
||||
}
|
||||
},
|
||||
'bar1'
|
||||
);
|
||||
})
|
||||
.toCompileTo('bar1');
|
||||
});
|
||||
|
||||
it('pass boolean literals', function() {
|
||||
shouldCompileTo('{{true}}', {}, '');
|
||||
shouldCompileTo('{{true}}', { '': 'foo' }, '');
|
||||
shouldCompileTo('{{false}}', { false: 'foo' }, 'foo');
|
||||
expectTemplate('{{true}}').toCompileTo('');
|
||||
|
||||
expectTemplate('{{true}}')
|
||||
.withInput({ '': 'foo' })
|
||||
.toCompileTo('');
|
||||
|
||||
expectTemplate('{{false}}')
|
||||
.withInput({ false: 'foo' })
|
||||
.toCompileTo('foo');
|
||||
});
|
||||
|
||||
it('should handle literals in subexpression', function() {
|
||||
var helpers = {
|
||||
foo: function(arg) {
|
||||
expectTemplate('{{foo (false)}}')
|
||||
.withInput({
|
||||
false: function() {
|
||||
return 'bar';
|
||||
}
|
||||
})
|
||||
.withHelper('foo', function(arg) {
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{foo (false)}}',
|
||||
[
|
||||
{
|
||||
false: function() {
|
||||
return 'bar';
|
||||
}
|
||||
},
|
||||
helpers
|
||||
],
|
||||
'bar'
|
||||
);
|
||||
})
|
||||
.toCompileTo('bar');
|
||||
});
|
||||
});
|
||||
|
||||
+286
-335
@@ -1,455 +1,405 @@
|
||||
describe('blocks', function() {
|
||||
it('array', function() {
|
||||
var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!';
|
||||
var hash = {
|
||||
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }],
|
||||
world: 'world'
|
||||
};
|
||||
shouldCompileTo(
|
||||
string,
|
||||
hash,
|
||||
'goodbye! Goodbye! GOODBYE! cruel world!',
|
||||
'Arrays iterate over the contents when not empty'
|
||||
);
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{ goodbyes: [], world: 'world' },
|
||||
'cruel world!',
|
||||
'Arrays ignore the contents when empty'
|
||||
);
|
||||
expectTemplate(string)
|
||||
.withInput({
|
||||
goodbyes: [
|
||||
{ text: 'goodbye' },
|
||||
{ text: 'Goodbye' },
|
||||
{ text: 'GOODBYE' }
|
||||
],
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('Arrays iterate over the contents when not empty')
|
||||
.toCompileTo('goodbye! Goodbye! GOODBYE! cruel world!');
|
||||
|
||||
expectTemplate(string)
|
||||
.withInput({
|
||||
goodbyes: [],
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('Arrays ignore the contents when empty')
|
||||
.toCompileTo('cruel world!');
|
||||
});
|
||||
|
||||
it('array without data', function() {
|
||||
var string =
|
||||
'{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}';
|
||||
var hash = {
|
||||
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }],
|
||||
world: 'world'
|
||||
};
|
||||
shouldCompileTo(
|
||||
string,
|
||||
[hash, , , false],
|
||||
'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}'
|
||||
)
|
||||
.withInput({
|
||||
goodbyes: [
|
||||
{ text: 'goodbye' },
|
||||
{ text: 'Goodbye' },
|
||||
{ text: 'GOODBYE' }
|
||||
],
|
||||
world: 'world'
|
||||
})
|
||||
.withCompileOptions({ compat: false })
|
||||
.toCompileTo('goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE');
|
||||
});
|
||||
|
||||
it('array with @index', function() {
|
||||
var string =
|
||||
'{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!';
|
||||
var hash = {
|
||||
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }],
|
||||
world: 'world'
|
||||
};
|
||||
|
||||
var template = CompilerContext.compile(string);
|
||||
var result = template(hash);
|
||||
|
||||
equal(
|
||||
result,
|
||||
'0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!',
|
||||
'The @index variable is used'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!'
|
||||
)
|
||||
.withInput({
|
||||
goodbyes: [
|
||||
{ text: 'goodbye' },
|
||||
{ text: 'Goodbye' },
|
||||
{ text: 'GOODBYE' }
|
||||
],
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('The @index variable is used')
|
||||
.toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!');
|
||||
});
|
||||
|
||||
it('empty block', function() {
|
||||
var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!';
|
||||
var hash = {
|
||||
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }],
|
||||
world: 'world'
|
||||
};
|
||||
shouldCompileTo(
|
||||
string,
|
||||
hash,
|
||||
'cruel world!',
|
||||
'Arrays iterate over the contents when not empty'
|
||||
);
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{ goodbyes: [], world: 'world' },
|
||||
'cruel world!',
|
||||
'Arrays ignore the contents when empty'
|
||||
);
|
||||
expectTemplate(string)
|
||||
.withInput({
|
||||
goodbyes: [
|
||||
{ text: 'goodbye' },
|
||||
{ text: 'Goodbye' },
|
||||
{ text: 'GOODBYE' }
|
||||
],
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('Arrays iterate over the contents when not empty')
|
||||
.toCompileTo('cruel world!');
|
||||
|
||||
expectTemplate(string)
|
||||
.withInput({
|
||||
goodbyes: [],
|
||||
world: 'world'
|
||||
})
|
||||
.withMessage('Arrays ignore the contents when empty')
|
||||
.toCompileTo('cruel world!');
|
||||
});
|
||||
|
||||
it('block with complex lookup', function() {
|
||||
var string = '{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}';
|
||||
var hash = {
|
||||
name: 'Alan',
|
||||
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }]
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
hash,
|
||||
'goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ',
|
||||
'Templates can access variables in contexts up the stack with relative path syntax'
|
||||
);
|
||||
expectTemplate('{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}')
|
||||
.withInput({
|
||||
name: 'Alan',
|
||||
goodbyes: [
|
||||
{ text: 'goodbye' },
|
||||
{ text: 'Goodbye' },
|
||||
{ text: 'GOODBYE' }
|
||||
]
|
||||
})
|
||||
.withMessage(
|
||||
'Templates can access variables in contexts up the stack with relative path syntax'
|
||||
)
|
||||
.toCompileTo(
|
||||
'goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! '
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple blocks with complex lookup', function() {
|
||||
var string = '{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}';
|
||||
var hash = {
|
||||
name: 'Alan',
|
||||
goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }, { text: 'GOODBYE' }]
|
||||
};
|
||||
|
||||
shouldCompileTo(string, hash, 'AlanAlanAlanAlanAlanAlan');
|
||||
expectTemplate('{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}')
|
||||
.withInput({
|
||||
name: 'Alan',
|
||||
goodbyes: [
|
||||
{ text: 'goodbye' },
|
||||
{ text: 'Goodbye' },
|
||||
{ text: 'GOODBYE' }
|
||||
]
|
||||
})
|
||||
.toCompileTo('AlanAlanAlanAlanAlanAlan');
|
||||
});
|
||||
|
||||
it('block with complex lookup using nested context', function() {
|
||||
var string = '{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}';
|
||||
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile(string);
|
||||
}, Error);
|
||||
expectTemplate(
|
||||
'{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}'
|
||||
).toThrow(Error);
|
||||
});
|
||||
|
||||
it('block with deep nested complex lookup', function() {
|
||||
var string =
|
||||
'{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}';
|
||||
var hash = {
|
||||
omg: 'OMG!',
|
||||
outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }]
|
||||
};
|
||||
|
||||
shouldCompileTo(string, hash, 'Goodbye cruel sad OMG!');
|
||||
expectTemplate(
|
||||
'{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}'
|
||||
)
|
||||
.withInput({
|
||||
omg: 'OMG!',
|
||||
outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }]
|
||||
})
|
||||
.toCompileTo('Goodbye cruel sad OMG!');
|
||||
});
|
||||
|
||||
it('works with cached blocks', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#each person}}{{#with .}}{{first}} {{last}}{{/with}}{{/each}}',
|
||||
{ data: false }
|
||||
);
|
||||
|
||||
var result = template({
|
||||
person: [
|
||||
{ first: 'Alan', last: 'Johnson' },
|
||||
{ first: 'Alan', last: 'Johnson' }
|
||||
]
|
||||
});
|
||||
equals(result, 'Alan JohnsonAlan Johnson');
|
||||
expectTemplate(
|
||||
'{{#each person}}{{#with .}}{{first}} {{last}}{{/with}}{{/each}}'
|
||||
)
|
||||
.withCompileOptions({ data: false })
|
||||
.withInput({
|
||||
person: [
|
||||
{ first: 'Alan', last: 'Johnson' },
|
||||
{ first: 'Alan', last: 'Johnson' }
|
||||
]
|
||||
})
|
||||
.toCompileTo('Alan JohnsonAlan Johnson');
|
||||
});
|
||||
|
||||
describe('inverted sections', function() {
|
||||
it('inverted sections with unset value', function() {
|
||||
var string =
|
||||
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||
var hash = {};
|
||||
shouldCompileTo(
|
||||
string,
|
||||
hash,
|
||||
'Right On!',
|
||||
"Inverted section rendered when value isn't set."
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'
|
||||
)
|
||||
.withMessage("Inverted section rendered when value isn't set.")
|
||||
.toCompileTo('Right On!');
|
||||
});
|
||||
|
||||
it('inverted section with false value', function() {
|
||||
var string =
|
||||
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||
var hash = { goodbyes: false };
|
||||
shouldCompileTo(
|
||||
string,
|
||||
hash,
|
||||
'Right On!',
|
||||
'Inverted section rendered when value is false.'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'
|
||||
)
|
||||
.withInput({ goodbyes: false })
|
||||
.withMessage('Inverted section rendered when value is false.')
|
||||
.toCompileTo('Right On!');
|
||||
});
|
||||
|
||||
it('inverted section with empty set', function() {
|
||||
var string =
|
||||
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
|
||||
var hash = { goodbyes: [] };
|
||||
shouldCompileTo(
|
||||
string,
|
||||
hash,
|
||||
'Right On!',
|
||||
'Inverted section rendered when value is empty set.'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'
|
||||
)
|
||||
.withInput({ goodbyes: [] })
|
||||
.withMessage('Inverted section rendered when value is empty set.')
|
||||
.toCompileTo('Right On!');
|
||||
});
|
||||
|
||||
it('block inverted sections', function() {
|
||||
shouldCompileTo(
|
||||
'{{#people}}{{name}}{{^}}{{none}}{{/people}}',
|
||||
{ none: 'No people' },
|
||||
'No people'
|
||||
);
|
||||
expectTemplate('{{#people}}{{name}}{{^}}{{none}}{{/people}}')
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people');
|
||||
});
|
||||
|
||||
it('chained inverted sections', function() {
|
||||
shouldCompileTo(
|
||||
'{{#people}}{{name}}{{else if none}}{{none}}{{/people}}',
|
||||
{ none: 'No people' },
|
||||
'No people'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}',
|
||||
{ none: 'No people' },
|
||||
'No people'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}',
|
||||
{ none: 'No people' },
|
||||
'No people'
|
||||
);
|
||||
expectTemplate('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}')
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people');
|
||||
|
||||
expectTemplate(
|
||||
'{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}'
|
||||
)
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people');
|
||||
|
||||
expectTemplate(
|
||||
'{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}'
|
||||
)
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people');
|
||||
});
|
||||
|
||||
it('chained inverted sections with mismatch', function() {
|
||||
shouldThrow(function() {
|
||||
shouldCompileTo(
|
||||
'{{#people}}{{name}}{{else if none}}{{none}}{{/if}}',
|
||||
{ none: 'No people' },
|
||||
'No people'
|
||||
);
|
||||
}, Error);
|
||||
expectTemplate(
|
||||
'{{#people}}{{name}}{{else if none}}{{none}}{{/if}}'
|
||||
).toThrow(Error);
|
||||
});
|
||||
|
||||
it('block inverted sections with empty arrays', function() {
|
||||
shouldCompileTo(
|
||||
'{{#people}}{{name}}{{^}}{{none}}{{/people}}',
|
||||
{ none: 'No people', people: [] },
|
||||
'No people'
|
||||
);
|
||||
expectTemplate('{{#people}}{{name}}{{^}}{{none}}{{/people}}')
|
||||
.withInput({
|
||||
none: 'No people',
|
||||
people: []
|
||||
})
|
||||
.toCompileTo('No people');
|
||||
});
|
||||
});
|
||||
|
||||
describe('standalone sections', function() {
|
||||
it('block standalone else sections', function() {
|
||||
shouldCompileTo(
|
||||
'{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n',
|
||||
{ none: 'No people' },
|
||||
'No people\n'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{#none}}\n{{.}}\n{{^}}\n{{none}}\n{{/none}}\n',
|
||||
{ none: 'No people' },
|
||||
'No people\n'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n',
|
||||
{ none: 'No people' },
|
||||
'No people\n'
|
||||
);
|
||||
expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n')
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people\n');
|
||||
|
||||
expectTemplate('{{#none}}\n{{.}}\n{{^}}\n{{none}}\n{{/none}}\n')
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people\n');
|
||||
|
||||
expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n')
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people\n');
|
||||
});
|
||||
|
||||
it('block standalone else sections can be disabled', function() {
|
||||
shouldCompileTo(
|
||||
'{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n',
|
||||
[{ none: 'No people' }, {}, {}, { ignoreStandalone: true }],
|
||||
'\nNo people\n\n'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{#none}}\n{{.}}\n{{^}}\nFail\n{{/none}}\n',
|
||||
[{ none: 'No people' }, {}, {}, { ignoreStandalone: true }],
|
||||
'\nNo people\n\n'
|
||||
);
|
||||
expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n')
|
||||
.withInput({ none: 'No people' })
|
||||
.withCompileOptions({ ignoreStandalone: true })
|
||||
.toCompileTo('\nNo people\n\n');
|
||||
|
||||
expectTemplate('{{#none}}\n{{.}}\n{{^}}\nFail\n{{/none}}\n')
|
||||
.withInput({ none: 'No people' })
|
||||
.withCompileOptions({ ignoreStandalone: true })
|
||||
.toCompileTo('\nNo people\n\n');
|
||||
});
|
||||
|
||||
it('block standalone chained else sections', function() {
|
||||
shouldCompileTo(
|
||||
'{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{/people}}\n',
|
||||
{ none: 'No people' },
|
||||
'No people\n'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{^}}\n{{/people}}\n',
|
||||
{ none: 'No people' },
|
||||
'No people\n'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{/people}}\n'
|
||||
)
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people\n');
|
||||
|
||||
expectTemplate(
|
||||
'{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{^}}\n{{/people}}\n'
|
||||
)
|
||||
.withInput({ none: 'No people' })
|
||||
.toCompileTo('No people\n');
|
||||
});
|
||||
|
||||
it('should handle nesting', function() {
|
||||
shouldCompileTo(
|
||||
'{{#data}}\n{{#if true}}\n{{.}}\n{{/if}}\n{{/data}}\nOK.',
|
||||
{ data: [1, 3, 5] },
|
||||
'1\n3\n5\nOK.'
|
||||
);
|
||||
expectTemplate('{{#data}}\n{{#if true}}\n{{.}}\n{{/if}}\n{{/data}}\nOK.')
|
||||
.withInput({
|
||||
data: [1, 3, 5]
|
||||
})
|
||||
.toCompileTo('1\n3\n5\nOK.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('compat mode', function() {
|
||||
it('block with deep recursive lookup lookup', function() {
|
||||
var string =
|
||||
'{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}';
|
||||
var hash = { omg: 'OMG!', outer: [{ inner: [{ text: 'goodbye' }] }] };
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
[hash, undefined, undefined, true],
|
||||
'Goodbye cruel OMG!'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}'
|
||||
)
|
||||
.withInput({ omg: 'OMG!', outer: [{ inner: [{ text: 'goodbye' }] }] })
|
||||
.withCompileOptions({ compat: true })
|
||||
.toCompileTo('Goodbye cruel OMG!');
|
||||
});
|
||||
|
||||
it('block with deep recursive pathed lookup', function() {
|
||||
var string =
|
||||
'{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
|
||||
var hash = {
|
||||
omg: { yes: 'OMG!' },
|
||||
outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }]
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
[hash, undefined, undefined, true],
|
||||
'Goodbye cruel OMG!'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}'
|
||||
)
|
||||
.withInput({
|
||||
omg: { yes: 'OMG!' },
|
||||
outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }]
|
||||
})
|
||||
.withCompileOptions({ compat: true })
|
||||
.toCompileTo('Goodbye cruel OMG!');
|
||||
});
|
||||
it('block with missed recursive lookup', function() {
|
||||
var string =
|
||||
'{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
|
||||
var hash = {
|
||||
omg: { no: 'OMG!' },
|
||||
outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }]
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
[hash, undefined, undefined, true],
|
||||
'Goodbye cruel '
|
||||
);
|
||||
it('block with missed recursive lookup', function() {
|
||||
expectTemplate(
|
||||
'{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}'
|
||||
)
|
||||
.withInput({
|
||||
omg: { no: 'OMG!' },
|
||||
outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }]
|
||||
})
|
||||
.withCompileOptions({ compat: true })
|
||||
.toCompileTo('Goodbye cruel ');
|
||||
});
|
||||
});
|
||||
|
||||
describe('decorators', function() {
|
||||
it('should apply mustache decorators', function() {
|
||||
var helpers = {
|
||||
helper: function(options) {
|
||||
expectTemplate('{{#helper}}{{*decorator}}{{/helper}}')
|
||||
.withHelper('helper', function(options) {
|
||||
return options.fn.run;
|
||||
}
|
||||
};
|
||||
var decorators = {
|
||||
decorator: function(fn) {
|
||||
})
|
||||
.withDecorator('decorator', function(fn) {
|
||||
fn.run = 'success';
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{#helper}}{{*decorator}}{{/helper}}',
|
||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||
'success'
|
||||
);
|
||||
})
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should apply allow undefined return', function() {
|
||||
var helpers = {
|
||||
helper: function(options) {
|
||||
expectTemplate('{{#helper}}{{*decorator}}suc{{/helper}}')
|
||||
.withHelper('helper', function(options) {
|
||||
return options.fn() + options.fn.run;
|
||||
}
|
||||
};
|
||||
var decorators = {
|
||||
decorator: function(fn) {
|
||||
})
|
||||
.withDecorator('decorator', function(fn) {
|
||||
fn.run = 'cess';
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{#helper}}{{*decorator}}suc{{/helper}}',
|
||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||
'success'
|
||||
);
|
||||
})
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should apply block decorators', function() {
|
||||
var helpers = {
|
||||
helper: function(options) {
|
||||
expectTemplate(
|
||||
'{{#helper}}{{#*decorator}}success{{/decorator}}{{/helper}}'
|
||||
)
|
||||
.withHelper('helper', function(options) {
|
||||
return options.fn.run;
|
||||
}
|
||||
};
|
||||
var decorators = {
|
||||
decorator: function(fn, props, container, options) {
|
||||
})
|
||||
.withDecorator('decorator', function(fn, props, container, options) {
|
||||
fn.run = options.fn();
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{#helper}}{{#*decorator}}success{{/decorator}}{{/helper}}',
|
||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||
'success'
|
||||
);
|
||||
})
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should support nested decorators', function() {
|
||||
var helpers = {
|
||||
helper: function(options) {
|
||||
expectTemplate(
|
||||
'{{#helper}}{{#*decorator}}{{#*nested}}suc{{/nested}}cess{{/decorator}}{{/helper}}'
|
||||
)
|
||||
.withHelper('helper', function(options) {
|
||||
return options.fn.run;
|
||||
}
|
||||
};
|
||||
var decorators = {
|
||||
decorator: function(fn, props, container, options) {
|
||||
fn.run = options.fn.nested + options.fn();
|
||||
return fn;
|
||||
},
|
||||
nested: function(fn, props, container, options) {
|
||||
props.nested = options.fn();
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{#helper}}{{#*decorator}}{{#*nested}}suc{{/nested}}cess{{/decorator}}{{/helper}}',
|
||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||
'success'
|
||||
);
|
||||
})
|
||||
.withDecorators({
|
||||
decorator: function(fn, props, container, options) {
|
||||
fn.run = options.fn.nested + options.fn();
|
||||
return fn;
|
||||
},
|
||||
nested: function(fn, props, container, options) {
|
||||
props.nested = options.fn();
|
||||
}
|
||||
})
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should apply multiple decorators', function() {
|
||||
var helpers = {
|
||||
helper: function(options) {
|
||||
expectTemplate(
|
||||
'{{#helper}}{{#*decorator}}suc{{/decorator}}{{#*decorator}}cess{{/decorator}}{{/helper}}'
|
||||
)
|
||||
.withHelper('helper', function(options) {
|
||||
return options.fn.run;
|
||||
}
|
||||
};
|
||||
var decorators = {
|
||||
decorator: function(fn, props, container, options) {
|
||||
})
|
||||
.withDecorator('decorator', function(fn, props, container, options) {
|
||||
fn.run = (fn.run || '') + options.fn();
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{#helper}}{{#*decorator}}suc{{/decorator}}{{#*decorator}}cess{{/decorator}}{{/helper}}',
|
||||
{ hash: {}, helpers: helpers, decorators: decorators },
|
||||
'success'
|
||||
);
|
||||
})
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should access parent variables', function() {
|
||||
var helpers = {
|
||||
helper: function(options) {
|
||||
expectTemplate('{{#helper}}{{*decorator foo}}{{/helper}}')
|
||||
.withHelper('helper', function(options) {
|
||||
return options.fn.run;
|
||||
}
|
||||
};
|
||||
var decorators = {
|
||||
decorator: function(fn, props, container, options) {
|
||||
})
|
||||
.withDecorator('decorator', function(fn, props, container, options) {
|
||||
fn.run = options.args;
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{#helper}}{{*decorator foo}}{{/helper}}',
|
||||
{ hash: { foo: 'success' }, helpers: helpers, decorators: decorators },
|
||||
'success'
|
||||
);
|
||||
})
|
||||
.withInput({ foo: 'success' })
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should work with root program', function() {
|
||||
var run;
|
||||
var decorators = {
|
||||
decorator: function(fn, props, container, options) {
|
||||
expectTemplate('{{*decorator "success"}}')
|
||||
.withDecorator('decorator', function(fn, props, container, options) {
|
||||
equals(options.args[0], 'success');
|
||||
run = true;
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{*decorator "success"}}',
|
||||
{ hash: { foo: 'success' }, decorators: decorators },
|
||||
''
|
||||
);
|
||||
})
|
||||
.withInput({ foo: 'success' })
|
||||
.toCompileTo('');
|
||||
equals(run, true);
|
||||
});
|
||||
|
||||
it('should fail when accessing variables from root', function() {
|
||||
var run;
|
||||
var decorators = {
|
||||
decorator: function(fn, props, container, options) {
|
||||
expectTemplate('{{*decorator foo}}')
|
||||
.withDecorator('decorator', function(fn, props, container, options) {
|
||||
equals(options.args[0], undefined);
|
||||
run = true;
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
'{{*decorator foo}}',
|
||||
{ hash: { foo: 'fail' }, decorators: decorators },
|
||||
''
|
||||
);
|
||||
})
|
||||
.withInput({ foo: 'fail' })
|
||||
.toCompileTo('');
|
||||
equals(run, true);
|
||||
});
|
||||
|
||||
@@ -481,6 +431,7 @@ describe('blocks', function() {
|
||||
equals(handlebarsEnv.decorators.foo, undefined);
|
||||
equals(handlebarsEnv.decorators.bar, undefined);
|
||||
});
|
||||
|
||||
it('fails with multiple and args', function() {
|
||||
shouldThrow(
|
||||
function() {
|
||||
|
||||
+454
-450
File diff suppressed because it is too large
Load Diff
+157
-243
@@ -1,31 +1,24 @@
|
||||
describe('data', function() {
|
||||
it('passing in data to a compiled function that expects data - works with helpers', function() {
|
||||
var template = CompilerContext.compile('{{hello}}', { data: true });
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
expectTemplate('{{hello}}')
|
||||
.withCompileOptions({ data: true })
|
||||
.withHelper('hello', function(options) {
|
||||
return options.data.adjective + ' ' + this.noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ noun: 'cat' },
|
||||
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||
);
|
||||
equals('happy cat', result, 'Data output by helper');
|
||||
})
|
||||
.withRuntimeOptions({ data: { adjective: 'happy' } })
|
||||
.withInput({ noun: 'cat' })
|
||||
.withMessage('Data output by helper')
|
||||
.toCompileTo('happy cat');
|
||||
});
|
||||
|
||||
it('data can be looked up via @foo', function() {
|
||||
var template = CompilerContext.compile('{{@hello}}');
|
||||
var result = template({}, { data: { hello: 'hello' } });
|
||||
equals('hello', result, '@foo retrieves template data');
|
||||
expectTemplate('{{@hello}}')
|
||||
.withRuntimeOptions({ data: { hello: 'hello' } })
|
||||
.withMessage('@foo retrieves template data')
|
||||
.toCompileTo('hello');
|
||||
});
|
||||
|
||||
it('deep @foo triggers automatic top-level data', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#let world="world"}}{{#if foo}}{{#if foo}}Hello {{@world}}{{/if}}{{/if}}{{/let}}'
|
||||
);
|
||||
|
||||
var helpers = Handlebars.createFrame(handlebarsEnv.helpers);
|
||||
|
||||
helpers.let = function(options) {
|
||||
@@ -39,124 +32,92 @@ describe('data', function() {
|
||||
return options.fn(this, { data: frame });
|
||||
};
|
||||
|
||||
var result = template({ foo: true }, { helpers: helpers });
|
||||
equals('Hello world', result, 'Automatic data was triggered');
|
||||
expectTemplate(
|
||||
'{{#let world="world"}}{{#if foo}}{{#if foo}}Hello {{@world}}{{/if}}{{/if}}{{/let}}'
|
||||
)
|
||||
.withInput({ foo: true })
|
||||
.withHelpers(helpers)
|
||||
.withMessage('Automatic data was triggered')
|
||||
.toCompileTo('Hello world');
|
||||
});
|
||||
|
||||
it('parameter data can be looked up via @foo', function() {
|
||||
var template = CompilerContext.compile('{{hello @world}}');
|
||||
var helpers = {
|
||||
hello: function(noun) {
|
||||
expectTemplate('{{hello @world}}')
|
||||
.withRuntimeOptions({ data: { world: 'world' } })
|
||||
.withHelper('hello', function(noun) {
|
||||
return 'Hello ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers, data: { world: 'world' } });
|
||||
equals(
|
||||
'Hello world',
|
||||
result,
|
||||
'@foo as a parameter retrieves template data'
|
||||
);
|
||||
})
|
||||
.withMessage('@foo as a parameter retrieves template data')
|
||||
.toCompileTo('Hello world');
|
||||
});
|
||||
|
||||
it('hash values can be looked up via @foo', function() {
|
||||
var template = CompilerContext.compile('{{hello noun=@world}}');
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
expectTemplate('{{hello noun=@world}}')
|
||||
.withRuntimeOptions({ data: { world: 'world' } })
|
||||
.withHelper('hello', function(options) {
|
||||
return 'Hello ' + options.hash.noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers, data: { world: 'world' } });
|
||||
equals(
|
||||
'Hello world',
|
||||
result,
|
||||
'@foo as a parameter retrieves template data'
|
||||
);
|
||||
})
|
||||
.withMessage('@foo as a parameter retrieves template data')
|
||||
.toCompileTo('Hello world');
|
||||
});
|
||||
|
||||
it('nested parameter data can be looked up via @foo.bar', function() {
|
||||
var template = CompilerContext.compile('{{hello @world.bar}}');
|
||||
var helpers = {
|
||||
hello: function(noun) {
|
||||
expectTemplate('{{hello @world.bar}}')
|
||||
.withRuntimeOptions({ data: { world: { bar: 'world' } } })
|
||||
.withHelper('hello', function(noun) {
|
||||
return 'Hello ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{},
|
||||
{ helpers: helpers, data: { world: { bar: 'world' } } }
|
||||
);
|
||||
equals(
|
||||
'Hello world',
|
||||
result,
|
||||
'@foo as a parameter retrieves template data'
|
||||
);
|
||||
})
|
||||
.withMessage('@foo as a parameter retrieves template data')
|
||||
.toCompileTo('Hello world');
|
||||
});
|
||||
|
||||
it('nested parameter data does not fail with @world.bar', function() {
|
||||
var template = CompilerContext.compile('{{hello @world.bar}}');
|
||||
var helpers = {
|
||||
hello: function(noun) {
|
||||
expectTemplate('{{hello @world.bar}}')
|
||||
.withRuntimeOptions({ data: { foo: { bar: 'world' } } })
|
||||
.withHelper('hello', function(noun) {
|
||||
return 'Hello ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{},
|
||||
{ helpers: helpers, data: { foo: { bar: 'world' } } }
|
||||
);
|
||||
equals(
|
||||
'Hello undefined',
|
||||
result,
|
||||
'@foo as a parameter retrieves template data'
|
||||
);
|
||||
})
|
||||
.withMessage('@foo as a parameter retrieves template data')
|
||||
.toCompileTo('Hello undefined');
|
||||
});
|
||||
|
||||
it('parameter data throws when using complex scope references', function() {
|
||||
var string = '{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}';
|
||||
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile(string);
|
||||
}, Error);
|
||||
expectTemplate(
|
||||
'{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}'
|
||||
).toThrow(Error);
|
||||
});
|
||||
|
||||
it('data can be functions', function() {
|
||||
var template = CompilerContext.compile('{{@hello}}');
|
||||
var result = template(
|
||||
{},
|
||||
{
|
||||
expectTemplate('{{@hello}}')
|
||||
.withRuntimeOptions({
|
||||
data: {
|
||||
hello: function() {
|
||||
return 'hello';
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
equals('hello', result);
|
||||
})
|
||||
.toCompileTo('hello');
|
||||
});
|
||||
|
||||
it('data can be functions with params', function() {
|
||||
var template = CompilerContext.compile('{{@hello "hello"}}');
|
||||
var result = template(
|
||||
{},
|
||||
{
|
||||
expectTemplate('{{@hello "hello"}}')
|
||||
.withRuntimeOptions({
|
||||
data: {
|
||||
hello: function(arg) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
equals('hello', result);
|
||||
})
|
||||
.toCompileTo('hello');
|
||||
});
|
||||
|
||||
it('data is inherited downstream', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}',
|
||||
{ data: true }
|
||||
);
|
||||
var helpers = {
|
||||
let: function(options) {
|
||||
expectTemplate(
|
||||
'{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}'
|
||||
)
|
||||
.withInput({ bar: { baz: 'hello world' } })
|
||||
.withCompileOptions({ data: true })
|
||||
.withHelper('let', function(options) {
|
||||
var frame = Handlebars.createFrame(options.data);
|
||||
for (var prop in options.hash) {
|
||||
if (prop in options.hash) {
|
||||
@@ -164,201 +125,154 @@ describe('data', function() {
|
||||
}
|
||||
}
|
||||
return options.fn(this, { data: frame });
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ bar: { baz: 'hello world' } },
|
||||
{ helpers: helpers, data: {} }
|
||||
);
|
||||
equals('2hello world1', result, 'data variables are inherited downstream');
|
||||
})
|
||||
.withRuntimeOptions({ data: {} })
|
||||
.withMessage('data variables are inherited downstream')
|
||||
.toCompileTo('2hello world1');
|
||||
});
|
||||
|
||||
it('passing in data to a compiled function that expects data - works with helpers in partials', function() {
|
||||
var template = CompilerContext.compile('{{>myPartial}}', { data: true });
|
||||
|
||||
var partials = {
|
||||
myPartial: CompilerContext.compile('{{hello}}', { data: true })
|
||||
};
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
expectTemplate('{{>myPartial}}')
|
||||
.withCompileOptions({ data: true })
|
||||
.withPartial('myPartial', '{{hello}}')
|
||||
.withHelper('hello', function(options) {
|
||||
return options.data.adjective + ' ' + this.noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ noun: 'cat' },
|
||||
{ helpers: helpers, partials: partials, data: { adjective: 'happy' } }
|
||||
);
|
||||
equals('happy cat', result, 'Data output by helper inside partial');
|
||||
})
|
||||
.withInput({ noun: 'cat' })
|
||||
.withRuntimeOptions({ data: { adjective: 'happy' } })
|
||||
.withMessage('Data output by helper inside partial')
|
||||
.toCompileTo('happy cat');
|
||||
});
|
||||
|
||||
it('passing in data to a compiled function that expects data - works with helpers and parameters', function() {
|
||||
var template = CompilerContext.compile('{{hello world}}', { data: true });
|
||||
|
||||
var helpers = {
|
||||
hello: function(noun, options) {
|
||||
expectTemplate('{{hello world}}')
|
||||
.withCompileOptions({ data: true })
|
||||
.withHelper('hello', function(noun, options) {
|
||||
return options.data.adjective + ' ' + noun + (this.exclaim ? '!' : '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ exclaim: true, world: 'world' },
|
||||
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||
);
|
||||
equals('happy world!', result, 'Data output by helper');
|
||||
})
|
||||
.withInput({ exclaim: true, world: 'world' })
|
||||
.withRuntimeOptions({ data: { adjective: 'happy' } })
|
||||
.withMessage('Data output by helper')
|
||||
.toCompileTo('happy world!');
|
||||
});
|
||||
|
||||
it('passing in data to a compiled function that expects data - works with block helpers', function() {
|
||||
var template = CompilerContext.compile('{{#hello}}{{world}}{{/hello}}', {
|
||||
data: true
|
||||
});
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
expectTemplate('{{#hello}}{{world}}{{/hello}}')
|
||||
.withCompileOptions({
|
||||
data: true
|
||||
})
|
||||
.withHelper('hello', function(options) {
|
||||
return options.fn(this);
|
||||
},
|
||||
world: function(options) {
|
||||
})
|
||||
.withHelper('world', function(options) {
|
||||
return options.data.adjective + ' world' + (this.exclaim ? '!' : '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ exclaim: true },
|
||||
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||
);
|
||||
equals('happy world!', result, 'Data output by helper');
|
||||
})
|
||||
.withInput({ exclaim: true })
|
||||
.withRuntimeOptions({ data: { adjective: 'happy' } })
|
||||
.withMessage('Data output by helper')
|
||||
.toCompileTo('happy world!');
|
||||
});
|
||||
|
||||
it('passing in data to a compiled function that expects data - works with block helpers that use ..', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#hello}}{{world ../zomg}}{{/hello}}',
|
||||
{ data: true }
|
||||
);
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}')
|
||||
.withCompileOptions({ data: true })
|
||||
.withHelper('hello', function(options) {
|
||||
return options.fn({ exclaim: '?' });
|
||||
},
|
||||
world: function(thing, options) {
|
||||
})
|
||||
.withHelper('world', function(thing, options) {
|
||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ exclaim: true, zomg: 'world' },
|
||||
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||
);
|
||||
equals('happy world?', result, 'Data output by helper');
|
||||
})
|
||||
.withInput({ exclaim: true, zomg: 'world' })
|
||||
.withRuntimeOptions({ data: { adjective: 'happy' } })
|
||||
.withMessage('Data output by helper')
|
||||
.toCompileTo('happy world?');
|
||||
});
|
||||
|
||||
it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#hello}}{{world ../zomg}}{{/hello}}',
|
||||
{ data: true }
|
||||
);
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}')
|
||||
.withCompileOptions({ data: true })
|
||||
.withHelper('hello', function(options) {
|
||||
return options.data.accessData + ' ' + options.fn({ exclaim: '?' });
|
||||
},
|
||||
world: function(thing, options) {
|
||||
})
|
||||
.withHelper('world', function(thing, options) {
|
||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ exclaim: true, zomg: 'world' },
|
||||
{ helpers: helpers, data: { adjective: 'happy', accessData: '#win' } }
|
||||
);
|
||||
equals('#win happy world?', result, 'Data output by helper');
|
||||
})
|
||||
.withInput({ exclaim: true, zomg: 'world' })
|
||||
.withRuntimeOptions({ data: { adjective: 'happy', accessData: '#win' } })
|
||||
.withMessage('Data output by helper')
|
||||
.toCompileTo('#win happy world?');
|
||||
});
|
||||
|
||||
it('you can override inherited data when invoking a helper', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#hello}}{{world zomg}}{{/hello}}',
|
||||
{ data: true }
|
||||
);
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
expectTemplate('{{#hello}}{{world zomg}}{{/hello}}')
|
||||
.withCompileOptions({ data: true })
|
||||
.withHelper('hello', function(options) {
|
||||
return options.fn(
|
||||
{ exclaim: '?', zomg: 'world' },
|
||||
{ data: { adjective: 'sad' } }
|
||||
);
|
||||
},
|
||||
world: function(thing, options) {
|
||||
})
|
||||
.withHelper('world', function(thing, options) {
|
||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ exclaim: true, zomg: 'planet' },
|
||||
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||
);
|
||||
equals('sad world?', result, 'Overriden data output by helper');
|
||||
})
|
||||
.withInput({ exclaim: true, zomg: 'planet' })
|
||||
.withRuntimeOptions({ data: { adjective: 'happy' } })
|
||||
.withMessage('Overriden data output by helper')
|
||||
.toCompileTo('sad world?');
|
||||
});
|
||||
|
||||
it('you can override inherited data when invoking a helper with depth', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#hello}}{{world ../zomg}}{{/hello}}',
|
||||
{ data: true }
|
||||
);
|
||||
|
||||
var helpers = {
|
||||
hello: function(options) {
|
||||
expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}')
|
||||
.withCompileOptions({ data: true })
|
||||
.withHelper('hello', function(options) {
|
||||
return options.fn({ exclaim: '?' }, { data: { adjective: 'sad' } });
|
||||
},
|
||||
world: function(thing, options) {
|
||||
})
|
||||
.withHelper('world', function(thing, options) {
|
||||
return options.data.adjective + ' ' + thing + (this.exclaim || '');
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{ exclaim: true, zomg: 'world' },
|
||||
{ helpers: helpers, data: { adjective: 'happy' } }
|
||||
);
|
||||
equals('sad world?', result, 'Overriden data output by helper');
|
||||
})
|
||||
.withInput({ exclaim: true, zomg: 'world' })
|
||||
.withRuntimeOptions({ data: { adjective: 'happy' } })
|
||||
.withMessage('Overriden data output by helper')
|
||||
.toCompileTo('sad world?');
|
||||
});
|
||||
|
||||
describe('@root', function() {
|
||||
it('the root context can be looked up via @root', function() {
|
||||
var template = CompilerContext.compile('{{@root.foo}}');
|
||||
var result = template({ foo: 'hello' }, { data: {} });
|
||||
equals('hello', result);
|
||||
expectTemplate('{{@root.foo}}')
|
||||
.withInput({ foo: 'hello' })
|
||||
.withRuntimeOptions({ data: {} })
|
||||
.toCompileTo('hello');
|
||||
|
||||
result = template({ foo: 'hello' }, {});
|
||||
equals('hello', result);
|
||||
expectTemplate('{{@root.foo}}')
|
||||
.withInput({ foo: 'hello' })
|
||||
.toCompileTo('hello');
|
||||
});
|
||||
|
||||
it('passed root values take priority', function() {
|
||||
var template = CompilerContext.compile('{{@root.foo}}');
|
||||
var result = template({}, { data: { root: { foo: 'hello' } } });
|
||||
equals('hello', result);
|
||||
expectTemplate('{{@root.foo}}')
|
||||
.withInput({ foo: 'should not be used' })
|
||||
.withRuntimeOptions({ data: { root: { foo: 'hello' } } })
|
||||
.toCompileTo('hello');
|
||||
});
|
||||
});
|
||||
|
||||
describe('nesting', function() {
|
||||
it('the root context can be looked up via @root', function() {
|
||||
var template = CompilerContext.compile(
|
||||
expectTemplate(
|
||||
'{{#helper}}{{#helper}}{{@./depth}} {{@../depth}} {{@../../depth}}{{/helper}}{{/helper}}'
|
||||
);
|
||||
var result = template(
|
||||
{ foo: 'hello' },
|
||||
{
|
||||
helpers: {
|
||||
helper: function(options) {
|
||||
var frame = Handlebars.createFrame(options.data);
|
||||
frame.depth = options.data.depth + 1;
|
||||
return options.fn(this, { data: frame });
|
||||
}
|
||||
},
|
||||
)
|
||||
.withInput({ foo: 'hello' })
|
||||
.withHelper('helper', function(options) {
|
||||
var frame = Handlebars.createFrame(options.data);
|
||||
frame.depth = options.data.depth + 1;
|
||||
return options.fn(this, { data: frame });
|
||||
})
|
||||
.withRuntimeOptions({
|
||||
data: {
|
||||
depth: 0
|
||||
}
|
||||
}
|
||||
);
|
||||
equals('2 1 0', result);
|
||||
})
|
||||
.toCompileTo('2 1 0');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Vendored
+40
-7
@@ -129,6 +129,7 @@ function HandlebarsTestBench(templateAsString) {
|
||||
this.templateAsString = templateAsString;
|
||||
this.helpers = {};
|
||||
this.partials = {};
|
||||
this.decorators = {};
|
||||
this.input = {};
|
||||
this.message =
|
||||
'Template' + templateAsString + ' does not evaluate to expected output';
|
||||
@@ -146,11 +147,43 @@ HandlebarsTestBench.prototype.withHelper = function(name, helperFunction) {
|
||||
return this;
|
||||
};
|
||||
|
||||
HandlebarsTestBench.prototype.withHelpers = function(helperFunctions) {
|
||||
var self = this;
|
||||
Object.keys(helperFunctions).forEach(function(name) {
|
||||
self.withHelper(name, helperFunctions[name]);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
HandlebarsTestBench.prototype.withPartial = function(name, partialAsString) {
|
||||
this.partials[name] = partialAsString;
|
||||
return this;
|
||||
};
|
||||
|
||||
HandlebarsTestBench.prototype.withPartials = function(partials) {
|
||||
var self = this;
|
||||
Object.keys(partials).forEach(function(name) {
|
||||
self.withPartial(name, partials[name]);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
HandlebarsTestBench.prototype.withDecorator = function(
|
||||
name,
|
||||
decoratorFunction
|
||||
) {
|
||||
this.decorators[name] = decoratorFunction;
|
||||
return this;
|
||||
};
|
||||
|
||||
HandlebarsTestBench.prototype.withDecorators = function(decorators) {
|
||||
var self = this;
|
||||
Object.keys(decorators).forEach(function(name) {
|
||||
self.withDecorator(name, decorators[name]);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
HandlebarsTestBench.prototype.withCompileOptions = function(compileOptions) {
|
||||
this.compileOptions = compileOptions;
|
||||
return this;
|
||||
@@ -167,19 +200,18 @@ HandlebarsTestBench.prototype.withMessage = function(message) {
|
||||
};
|
||||
|
||||
HandlebarsTestBench.prototype.toCompileTo = function(expectedOutputAsString) {
|
||||
expect(this._compileAndExecute()).to.equal(expectedOutputAsString);
|
||||
expect(this._compileAndExecute()).to.equal(
|
||||
expectedOutputAsString,
|
||||
this.message
|
||||
);
|
||||
};
|
||||
|
||||
// see chai "to.throw" (https://www.chaijs.com/api/bdd/#method_throw)
|
||||
HandlebarsTestBench.prototype.toThrow = function(
|
||||
errorLike,
|
||||
errMsgMatcher,
|
||||
msg
|
||||
) {
|
||||
HandlebarsTestBench.prototype.toThrow = function(errorLike, errMsgMatcher) {
|
||||
var self = this;
|
||||
expect(function() {
|
||||
self._compileAndExecute();
|
||||
}).to.throw(errorLike, errMsgMatcher, msg);
|
||||
}).to.throw(errorLike, errMsgMatcher, this.message);
|
||||
};
|
||||
|
||||
HandlebarsTestBench.prototype._compileAndExecute = function() {
|
||||
@@ -202,5 +234,6 @@ HandlebarsTestBench.prototype._combineRuntimeOptions = function() {
|
||||
});
|
||||
combinedRuntimeOptions.helpers = this.helpers;
|
||||
combinedRuntimeOptions.partials = this.partials;
|
||||
combinedRuntimeOptions.decorators = this.decorators;
|
||||
return combinedRuntimeOptions;
|
||||
};
|
||||
|
||||
+527
-822
File diff suppressed because it is too large
Load Diff
@@ -20,14 +20,18 @@ describe('javascript-compiler api', function() {
|
||||
return parent + '.bar_' + name;
|
||||
};
|
||||
/* eslint-disable camelcase */
|
||||
shouldCompileTo('{{foo}}', { bar_foo: 'food' }, 'food');
|
||||
expectTemplate('{{foo}}')
|
||||
.withInput({ bar_foo: 'food' })
|
||||
.toCompileTo('food');
|
||||
/* eslint-enable camelcase */
|
||||
});
|
||||
|
||||
// Tests nameLookup dot vs. bracket behavior. Bracket is required in certain cases
|
||||
// to avoid errors in older browsers.
|
||||
it('should handle reserved words', function() {
|
||||
shouldCompileTo('{{foo}} {{~null~}}', { foo: 'food' }, 'food');
|
||||
expectTemplate('{{foo}} {{~null~}}')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('food');
|
||||
});
|
||||
});
|
||||
describe('#compilerInfo', function() {
|
||||
@@ -49,7 +53,9 @@ describe('javascript-compiler api', function() {
|
||||
throw new Error("It didn't work");
|
||||
}
|
||||
};
|
||||
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'food ');
|
||||
expectTemplate('{{foo}} ')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('food ');
|
||||
});
|
||||
});
|
||||
describe('buffer', function() {
|
||||
@@ -70,7 +76,9 @@ describe('javascript-compiler api', function() {
|
||||
handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = function() {
|
||||
return this.quotedString('foo_');
|
||||
};
|
||||
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'foo_food ');
|
||||
expectTemplate('{{foo}} ')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('foo_food ');
|
||||
});
|
||||
it('should allow append buffer override', function() {
|
||||
handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function(
|
||||
@@ -78,7 +86,9 @@ describe('javascript-compiler api', function() {
|
||||
) {
|
||||
return $superAppend.call(this, [string, ' + "_foo"']);
|
||||
};
|
||||
shouldCompileTo('{{foo}}', { foo: 'food' }, 'food_foo');
|
||||
expectTemplate('{{foo}}')
|
||||
.withInput({ foo: 'food' })
|
||||
.toCompileTo('food_foo');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+442
-606
File diff suppressed because it is too large
Load Diff
+217
-244
@@ -1,61 +1,53 @@
|
||||
describe('Regressions', function() {
|
||||
it('GH-94: Cannot read property of undefined', function() {
|
||||
var data = {
|
||||
books: [
|
||||
{
|
||||
title: 'The origin of species',
|
||||
author: {
|
||||
name: 'Charles Darwin'
|
||||
expectTemplate('{{#books}}{{title}}{{author.name}}{{/books}}')
|
||||
.withInput({
|
||||
books: [
|
||||
{
|
||||
title: 'The origin of species',
|
||||
author: {
|
||||
name: 'Charles Darwin'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Lazarillo de Tormes'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Lazarillo de Tormes'
|
||||
}
|
||||
]
|
||||
};
|
||||
var string = '{{#books}}{{title}}{{author.name}}{{/books}}';
|
||||
shouldCompileTo(
|
||||
string,
|
||||
data,
|
||||
'The origin of speciesCharles DarwinLazarillo de Tormes',
|
||||
'Renders without an undefined property error'
|
||||
);
|
||||
]
|
||||
})
|
||||
.withMessage('Renders without an undefined property error')
|
||||
.toCompileTo('The origin of speciesCharles DarwinLazarillo de Tormes');
|
||||
});
|
||||
|
||||
it("GH-150: Inverted sections print when they shouldn't", function() {
|
||||
var string = '{{^set}}not set{{/set}} :: {{#set}}set{{/set}}';
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{},
|
||||
'not set :: ',
|
||||
"inverted sections run when property isn't present in context"
|
||||
);
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{ set: undefined },
|
||||
'not set :: ',
|
||||
'inverted sections run when property is undefined'
|
||||
);
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{ set: false },
|
||||
'not set :: ',
|
||||
'inverted sections run when property is false'
|
||||
);
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{ set: true },
|
||||
' :: set',
|
||||
"inverted sections don't run when property is true"
|
||||
);
|
||||
expectTemplate(string)
|
||||
.withMessage(
|
||||
"inverted sections run when property isn't present in context"
|
||||
)
|
||||
.toCompileTo('not set :: ');
|
||||
|
||||
expectTemplate(string)
|
||||
.withInput({ set: undefined })
|
||||
.withMessage('inverted sections run when property is undefined')
|
||||
.toCompileTo('not set :: ');
|
||||
|
||||
expectTemplate(string)
|
||||
.withInput({ set: false })
|
||||
.withMessage('inverted sections run when property is false')
|
||||
.toCompileTo('not set :: ');
|
||||
|
||||
expectTemplate(string)
|
||||
.withInput({ set: true })
|
||||
.withMessage("inverted sections don't run when property is true")
|
||||
.toCompileTo(' :: set');
|
||||
});
|
||||
|
||||
it('GH-158: Using array index twice, breaks the template', function() {
|
||||
var string = '{{arr.[0]}}, {{arr.[1]}}';
|
||||
var data = { arr: [1, 2] };
|
||||
|
||||
shouldCompileTo(string, data, '1, 2', 'it works as expected');
|
||||
expectTemplate('{{arr.[0]}}, {{arr.[1]}}')
|
||||
.withInput({ arr: [1, 2] })
|
||||
.withMessage('it works as expected')
|
||||
.toCompileTo('1, 2');
|
||||
});
|
||||
|
||||
it("bug reported by @fat where lambdas weren't being properly resolved", function() {
|
||||
@@ -73,6 +65,7 @@ describe('Regressions', function() {
|
||||
'\n' +
|
||||
'<small>Nothing to check out...</small>\n' +
|
||||
'{{/hasThings}}';
|
||||
|
||||
var data = {
|
||||
thing: function() {
|
||||
return 'blah';
|
||||
@@ -95,25 +88,22 @@ describe('Regressions', function() {
|
||||
'<li class=two>@dhg</li>\n' +
|
||||
'<li class=three>@sayrer</li>\n' +
|
||||
'</ul>.\n';
|
||||
shouldCompileTo(string, data, output);
|
||||
|
||||
expectTemplate(string)
|
||||
.withInput(data)
|
||||
.toCompileTo(output);
|
||||
});
|
||||
|
||||
it('GH-408: Multiple loops fail', function() {
|
||||
var context = [
|
||||
{ name: 'John Doe', location: { city: 'Chicago' } },
|
||||
{ name: 'Jane Doe', location: { city: 'New York' } }
|
||||
];
|
||||
|
||||
var template = CompilerContext.compile(
|
||||
expectTemplate(
|
||||
'{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}'
|
||||
);
|
||||
|
||||
var result = template(context);
|
||||
equals(
|
||||
result,
|
||||
'John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe',
|
||||
'It should output multiple times'
|
||||
);
|
||||
)
|
||||
.withInput([
|
||||
{ name: 'John Doe', location: { city: 'Chicago' } },
|
||||
{ name: 'Jane Doe', location: { city: 'New York' } }
|
||||
])
|
||||
.withMessage('It should output multiple times')
|
||||
.toCompileTo('John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe');
|
||||
});
|
||||
|
||||
it('GS-428: Nested if else rendering', function() {
|
||||
@@ -131,259 +121,242 @@ describe('Regressions', function() {
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo(succeedingTemplate, [{}, helpers], ' Expected ');
|
||||
shouldCompileTo(failingTemplate, [{}, helpers], ' Expected ');
|
||||
expectTemplate(succeedingTemplate)
|
||||
.withHelpers(helpers)
|
||||
.toCompileTo(' Expected ');
|
||||
|
||||
expectTemplate(failingTemplate)
|
||||
.withHelpers(helpers)
|
||||
.toCompileTo(' Expected ');
|
||||
});
|
||||
|
||||
it('GH-458: Scoped this identifier', function() {
|
||||
shouldCompileTo('{{./foo}}', { foo: 'bar' }, 'bar');
|
||||
expectTemplate('{{./foo}}')
|
||||
.withInput({ foo: 'bar' })
|
||||
.toCompileTo('bar');
|
||||
});
|
||||
|
||||
it('GH-375: Unicode line terminators', function() {
|
||||
shouldCompileTo('\u2028', {}, '\u2028');
|
||||
expectTemplate('\u2028').toCompileTo('\u2028');
|
||||
});
|
||||
|
||||
it('GH-534: Object prototype aliases', function() {
|
||||
/* eslint-disable no-extend-native */
|
||||
Object.prototype[0xd834] = true;
|
||||
|
||||
shouldCompileTo('{{foo}}', { foo: 'bar' }, 'bar');
|
||||
expectTemplate('{{foo}}')
|
||||
.withInput({ foo: 'bar' })
|
||||
.toCompileTo('bar');
|
||||
|
||||
delete Object.prototype[0xd834];
|
||||
/* eslint-enable no-extend-native */
|
||||
});
|
||||
|
||||
it('GH-437: Matching escaping', function() {
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile('{{{a}}');
|
||||
}, Error);
|
||||
shouldThrow(function() {
|
||||
CompilerContext.compile('{{a}}}');
|
||||
}, Error);
|
||||
expectTemplate('{{{a}}').toThrow(Error, /Parse error on/);
|
||||
expectTemplate('{{a}}}').toThrow(Error, /Parse error on/);
|
||||
});
|
||||
|
||||
it('GH-676: Using array in escaping mustache fails', function() {
|
||||
var string = '{{arr}}';
|
||||
var data = { arr: [1, 2] };
|
||||
|
||||
shouldCompileTo(string, data, data.arr.toString(), 'it works as expected');
|
||||
expectTemplate('{{arr}}')
|
||||
.withInput(data)
|
||||
.withMessage('it works as expected')
|
||||
.toCompileTo(data.arr.toString());
|
||||
});
|
||||
|
||||
it('Mustache man page', function() {
|
||||
var string =
|
||||
'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}';
|
||||
var data = {
|
||||
name: 'Chris',
|
||||
value: 10000,
|
||||
taxed_value: 10000 - 10000 * 0.4,
|
||||
in_ca: true
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
string,
|
||||
data,
|
||||
'Hello Chris. You have just won $10000! Well, $6000, after taxes.',
|
||||
'the hello world mustache example works'
|
||||
);
|
||||
expectTemplate(
|
||||
'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}'
|
||||
)
|
||||
.withInput({
|
||||
name: 'Chris',
|
||||
value: 10000,
|
||||
taxed_value: 10000 - 10000 * 0.4,
|
||||
in_ca: true
|
||||
})
|
||||
.withMessage('the hello world mustache example works')
|
||||
.toCompileTo(
|
||||
'Hello Chris. You have just won $10000! Well, $6000, after taxes.'
|
||||
);
|
||||
});
|
||||
|
||||
it('GH-731: zero context rendering', function() {
|
||||
shouldCompileTo(
|
||||
'{{#foo}} This is {{bar}} ~ {{/foo}}',
|
||||
{ foo: 0, bar: 'OK' },
|
||||
' This is ~ '
|
||||
);
|
||||
expectTemplate('{{#foo}} This is {{bar}} ~ {{/foo}}')
|
||||
.withInput({
|
||||
foo: 0,
|
||||
bar: 'OK'
|
||||
})
|
||||
.toCompileTo(' This is ~ ');
|
||||
});
|
||||
|
||||
it('GH-820: zero pathed rendering', function() {
|
||||
shouldCompileTo('{{foo.bar}}', { foo: 0 }, '');
|
||||
expectTemplate('{{foo.bar}}')
|
||||
.withInput({ foo: 0 })
|
||||
.toCompileTo('');
|
||||
});
|
||||
|
||||
it('GH-837: undefined values for helpers', function() {
|
||||
var helpers = {
|
||||
str: function(value) {
|
||||
return value + '';
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo('{{str bar.baz}}', [{}, helpers], 'undefined');
|
||||
expectTemplate('{{str bar.baz}}')
|
||||
.withHelpers({
|
||||
str: function(value) {
|
||||
return value + '';
|
||||
}
|
||||
})
|
||||
.toCompileTo('undefined');
|
||||
});
|
||||
|
||||
it('GH-926: Depths and de-dupe', function() {
|
||||
var context = {
|
||||
name: 'foo',
|
||||
data: [1],
|
||||
notData: [1]
|
||||
};
|
||||
|
||||
var template = CompilerContext.compile(
|
||||
expectTemplate(
|
||||
'{{#if dater}}{{#each data}}{{../name}}{{/each}}{{else}}{{#each notData}}{{../name}}{{/each}}{{/if}}'
|
||||
);
|
||||
|
||||
var result = template(context);
|
||||
equals(result, 'foo');
|
||||
)
|
||||
.withInput({
|
||||
name: 'foo',
|
||||
data: [1],
|
||||
notData: [1]
|
||||
})
|
||||
.toCompileTo('foo');
|
||||
});
|
||||
|
||||
it('GH-1021: Each empty string key', function() {
|
||||
var data = {
|
||||
'': 'foo',
|
||||
name: 'Chris',
|
||||
value: 10000
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
'{{#each data}}Key: {{@key}}\n{{/each}}',
|
||||
{ data: data },
|
||||
'Key: \nKey: name\nKey: value\n'
|
||||
);
|
||||
expectTemplate('{{#each data}}Key: {{@key}}\n{{/each}}')
|
||||
.withInput({
|
||||
data: {
|
||||
'': 'foo',
|
||||
name: 'Chris',
|
||||
value: 10000
|
||||
}
|
||||
})
|
||||
.toCompileTo('Key: \nKey: name\nKey: value\n');
|
||||
});
|
||||
|
||||
it('GH-1054: Should handle simple safe string responses', function() {
|
||||
var root = '{{#wrap}}{{>partial}}{{/wrap}}';
|
||||
var partials = {
|
||||
partial: '{{#wrap}}<partial>{{/wrap}}'
|
||||
};
|
||||
var helpers = {
|
||||
wrap: function(options) {
|
||||
return new Handlebars.SafeString(options.fn());
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileToWithPartials(
|
||||
root,
|
||||
[{}, helpers, partials],
|
||||
true,
|
||||
'<partial>'
|
||||
);
|
||||
expectTemplate('{{#wrap}}{{>partial}}{{/wrap}}')
|
||||
.withHelpers({
|
||||
wrap: function(options) {
|
||||
return new Handlebars.SafeString(options.fn());
|
||||
}
|
||||
})
|
||||
.withPartials({
|
||||
partial: '{{#wrap}}<partial>{{/wrap}}'
|
||||
})
|
||||
.toCompileTo('<partial>');
|
||||
});
|
||||
|
||||
it('GH-1065: Sparse arrays', function() {
|
||||
var array = [];
|
||||
array[1] = 'foo';
|
||||
array[3] = 'bar';
|
||||
shouldCompileTo(
|
||||
'{{#each array}}{{@index}}{{.}}{{/each}}',
|
||||
{ array: array },
|
||||
'1foo3bar'
|
||||
);
|
||||
expectTemplate('{{#each array}}{{@index}}{{.}}{{/each}}')
|
||||
.withInput({ array: array })
|
||||
.toCompileTo('1foo3bar');
|
||||
});
|
||||
|
||||
it('GH-1093: Undefined helper context', function() {
|
||||
var obj = { foo: undefined, bar: 'bat' };
|
||||
var helpers = {
|
||||
helper: function() {
|
||||
// It's valid to execute a block against an undefined context, but
|
||||
// helpers can not do so, so we expect to have an empty object here;
|
||||
for (var name in this) {
|
||||
if (Object.prototype.hasOwnProperty.call(this, name)) {
|
||||
return 'found';
|
||||
expectTemplate('{{#each obj}}{{{helper}}}{{.}}{{/each}}')
|
||||
.withInput({ obj: { foo: undefined, bar: 'bat' } })
|
||||
.withHelpers({
|
||||
helper: function() {
|
||||
// It's valid to execute a block against an undefined context, but
|
||||
// helpers can not do so, so we expect to have an empty object here;
|
||||
for (var name in this) {
|
||||
if (Object.prototype.hasOwnProperty.call(this, name)) {
|
||||
return 'found';
|
||||
}
|
||||
}
|
||||
// And to make IE happy, check for the known string as length is not enumerated.
|
||||
return this === 'bat' ? 'found' : 'not';
|
||||
}
|
||||
// And to make IE happy, check for the known string as length is not enumerated.
|
||||
return this === 'bat' ? 'found' : 'not';
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
'{{#each obj}}{{{helper}}}{{.}}{{/each}}',
|
||||
[{ obj: obj }, helpers],
|
||||
'notfoundbat'
|
||||
);
|
||||
})
|
||||
.toCompileTo('notfoundbat');
|
||||
});
|
||||
|
||||
it('should support multiple levels of inline partials', function() {
|
||||
var string =
|
||||
'{{#> layout}}{{#*inline "subcontent"}}subcontent{{/inline}}{{/layout}}';
|
||||
var partials = {
|
||||
doctype: 'doctype{{> content}}',
|
||||
layout:
|
||||
'{{#> doctype}}{{#*inline "content"}}layout{{> subcontent}}{{/inline}}{{/doctype}}'
|
||||
};
|
||||
shouldCompileToWithPartials(
|
||||
string,
|
||||
[{}, {}, partials],
|
||||
true,
|
||||
'doctypelayoutsubcontent'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#> layout}}{{#*inline "subcontent"}}subcontent{{/inline}}{{/layout}}'
|
||||
)
|
||||
.withPartials({
|
||||
doctype: 'doctype{{> content}}',
|
||||
layout:
|
||||
'{{#> doctype}}{{#*inline "content"}}layout{{> subcontent}}{{/inline}}{{/doctype}}'
|
||||
})
|
||||
.toCompileTo('doctypelayoutsubcontent');
|
||||
});
|
||||
|
||||
it('GH-1089: should support failover content in multiple levels of inline partials', function() {
|
||||
var string = '{{#> layout}}{{/layout}}';
|
||||
var partials = {
|
||||
doctype: 'doctype{{> content}}',
|
||||
layout:
|
||||
'{{#> doctype}}{{#*inline "content"}}layout{{#> subcontent}}subcontent{{/subcontent}}{{/inline}}{{/doctype}}'
|
||||
};
|
||||
shouldCompileToWithPartials(
|
||||
string,
|
||||
[{}, {}, partials],
|
||||
true,
|
||||
'doctypelayoutsubcontent'
|
||||
);
|
||||
expectTemplate('{{#> layout}}{{/layout}}')
|
||||
.withPartials({
|
||||
doctype: 'doctype{{> content}}',
|
||||
layout:
|
||||
'{{#> doctype}}{{#*inline "content"}}layout{{#> subcontent}}subcontent{{/subcontent}}{{/inline}}{{/doctype}}'
|
||||
})
|
||||
.toCompileTo('doctypelayoutsubcontent');
|
||||
});
|
||||
|
||||
it('GH-1099: should support greater than 3 nested levels of inline partials', function() {
|
||||
var string = '{{#> layout}}Outer{{/layout}}';
|
||||
var partials = {
|
||||
layout: '{{#> inner}}Inner{{/inner}}{{> @partial-block }}',
|
||||
inner: ''
|
||||
};
|
||||
shouldCompileToWithPartials(string, [{}, {}, partials], true, 'Outer');
|
||||
expectTemplate('{{#> layout}}Outer{{/layout}}')
|
||||
.withPartials({
|
||||
layout: '{{#> inner}}Inner{{/inner}}{{> @partial-block }}',
|
||||
inner: ''
|
||||
})
|
||||
.toCompileTo('Outer');
|
||||
});
|
||||
|
||||
it('GH-1135 : Context handling within each iteration', function() {
|
||||
var obj = { array: [1], name: 'John' };
|
||||
var helpers = {
|
||||
myif: function(conditional, options) {
|
||||
if (conditional) {
|
||||
return options.fn(this);
|
||||
} else {
|
||||
return options.inverse(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
expectTemplate(
|
||||
'{{#each array}}\n' +
|
||||
' 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}}\n' +
|
||||
' 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}}\n' +
|
||||
'{{/each}}',
|
||||
[obj, helpers],
|
||||
' 1. IF: John--\n' + ' 2. MYIF: John==\n'
|
||||
);
|
||||
'{{/each}}'
|
||||
)
|
||||
.withInput({ array: [1], name: 'John' })
|
||||
.withHelpers({
|
||||
myif: function(conditional, options) {
|
||||
if (conditional) {
|
||||
return options.fn(this);
|
||||
} else {
|
||||
return options.inverse(this);
|
||||
}
|
||||
}
|
||||
})
|
||||
.toCompileTo(' 1. IF: John--\n' + ' 2. MYIF: John==\n');
|
||||
});
|
||||
|
||||
it('GH-1186: Support block params for existing programs', function() {
|
||||
var string =
|
||||
expectTemplate(
|
||||
'{{#*inline "test"}}{{> @partial-block }}{{/inline}}' +
|
||||
'{{#>test }}{{#each listOne as |item|}}{{ item }}{{/each}}{{/test}}' +
|
||||
'{{#>test }}{{#each listTwo as |item|}}{{ item }}{{/each}}{{/test}}';
|
||||
|
||||
shouldCompileTo(string, { listOne: ['a'], listTwo: ['b'] }, 'ab', '');
|
||||
'{{#>test }}{{#each listOne as |item|}}{{ item }}{{/each}}{{/test}}' +
|
||||
'{{#>test }}{{#each listTwo as |item|}}{{ item }}{{/each}}{{/test}}'
|
||||
)
|
||||
.withInput({
|
||||
listOne: ['a'],
|
||||
listTwo: ['b']
|
||||
})
|
||||
.withMessage('')
|
||||
.toCompileTo('ab');
|
||||
});
|
||||
|
||||
it('GH-1319: "unless" breaks when "each" value equals "null"', function() {
|
||||
var string =
|
||||
'{{#each list}}{{#unless ./prop}}parent={{../value}} {{/unless}}{{/each}}';
|
||||
shouldCompileTo(
|
||||
string,
|
||||
{ value: 'parent', list: [null, 'a'] },
|
||||
'parent=parent parent=parent ',
|
||||
''
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#each list}}{{#unless ./prop}}parent={{../value}} {{/unless}}{{/each}}'
|
||||
)
|
||||
.withInput({
|
||||
value: 'parent',
|
||||
list: [null, 'a']
|
||||
})
|
||||
.withMessage('')
|
||||
.toCompileTo('parent=parent parent=parent ');
|
||||
});
|
||||
|
||||
it('GH-1341: 4.0.7 release breaks {{#if @partial-block}} usage', function() {
|
||||
var string = 'template {{>partial}} template';
|
||||
var partials = {
|
||||
partialWithBlock:
|
||||
'{{#if @partial-block}} block {{> @partial-block}} block {{/if}}',
|
||||
partial: '{{#> partialWithBlock}} partial {{/partialWithBlock}}'
|
||||
};
|
||||
shouldCompileToWithPartials(
|
||||
string,
|
||||
[{}, {}, partials],
|
||||
true,
|
||||
'template block partial block template'
|
||||
);
|
||||
expectTemplate('template {{>partial}} template')
|
||||
.withPartials({
|
||||
partialWithBlock:
|
||||
'{{#if @partial-block}} block {{> @partial-block}} block {{/if}}',
|
||||
partial: '{{#> partialWithBlock}} partial {{/partialWithBlock}}'
|
||||
})
|
||||
.toCompileTo('template block partial block template');
|
||||
});
|
||||
|
||||
describe('GH-1561: 4.3.x should still work with precompiled templates from 4.0.0 <= x < 4.3.0', function() {
|
||||
@@ -482,14 +455,14 @@ describe('Regressions', function() {
|
||||
});
|
||||
|
||||
it('should allow hash with protected array names', function() {
|
||||
var obj = { array: [1], name: 'John' };
|
||||
var helpers = {
|
||||
helpa: function(options) {
|
||||
return options.hash.length;
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo('{{helpa length="foo"}}', [obj, helpers], 'foo');
|
||||
expectTemplate('{{helpa length="foo"}}')
|
||||
.withInput({ array: [1], name: 'John' })
|
||||
.withHelpers({
|
||||
helpa: function(options) {
|
||||
return options.hash.length;
|
||||
}
|
||||
})
|
||||
.toCompileTo('foo');
|
||||
});
|
||||
|
||||
describe('GH-1598: Performance degradation for partials since v4.3.0', function() {
|
||||
|
||||
+22
-44
@@ -20,36 +20,19 @@ describe('security issues', function() {
|
||||
});
|
||||
|
||||
it('should allow the "constructor" property to be accessed if it is an "ownProperty"', function() {
|
||||
shouldCompileTo(
|
||||
'{{constructor.name}}',
|
||||
{
|
||||
constructor: {
|
||||
name: 'here we go'
|
||||
}
|
||||
},
|
||||
'here we go'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'{{lookup (lookup this "constructor") "name"}}',
|
||||
{
|
||||
constructor: {
|
||||
name: 'here we go'
|
||||
}
|
||||
},
|
||||
'here we go'
|
||||
);
|
||||
expectTemplate('{{constructor.name}}')
|
||||
.withInput({ constructor: { name: 'here we go' } })
|
||||
.toCompileTo('here we go');
|
||||
|
||||
expectTemplate('{{lookup (lookup this "constructor") "name"}}')
|
||||
.withInput({ constructor: { name: 'here we go' } })
|
||||
.toCompileTo('here we go');
|
||||
});
|
||||
|
||||
it('should allow the "constructor" property to be accessed if it is an "own property"', function() {
|
||||
shouldCompileTo(
|
||||
'{{lookup (lookup this "constructor") "name"}}',
|
||||
{
|
||||
constructor: {
|
||||
name: 'here we go'
|
||||
}
|
||||
},
|
||||
'here we go'
|
||||
);
|
||||
expectTemplate('{{lookup (lookup this "constructor") "name"}}')
|
||||
.withInput({ constructor: { name: 'here we go' } })
|
||||
.toCompileTo('here we go');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,19 +43,13 @@ describe('security issues', function() {
|
||||
|
||||
describe('without the option "allowExplicitCallOfHelperMissing"', function() {
|
||||
it('should throw an exception when calling "{{helperMissing}}" ', function() {
|
||||
shouldThrow(function() {
|
||||
var template = Handlebars.compile('{{helperMissing}}');
|
||||
template({});
|
||||
}, Error);
|
||||
expectTemplate('{{helperMissing}}').toThrow(Error);
|
||||
});
|
||||
|
||||
it('should throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() {
|
||||
shouldThrow(function() {
|
||||
var template = Handlebars.compile(
|
||||
'{{#helperMissing}}{{/helperMissing}}'
|
||||
);
|
||||
template({});
|
||||
}, Error);
|
||||
expectTemplate('{{#helperMissing}}{{/helperMissing}}').toThrow(Error);
|
||||
});
|
||||
|
||||
it('should throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function() {
|
||||
var functionCalls = [];
|
||||
expect(function() {
|
||||
@@ -85,17 +62,15 @@ describe('security issues', function() {
|
||||
}).to.throw(Error);
|
||||
expect(functionCalls.length).to.equal(0);
|
||||
});
|
||||
|
||||
it('should throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function() {
|
||||
shouldThrow(function() {
|
||||
var template = Handlebars.compile(
|
||||
'{{#blockHelperMissing .}}{{/blockHelperMissing}}'
|
||||
);
|
||||
template({
|
||||
expectTemplate('{{#blockHelperMissing .}}{{/blockHelperMissing}}')
|
||||
.withInput({
|
||||
fn: function() {
|
||||
return 'functionInData';
|
||||
}
|
||||
});
|
||||
}, Error);
|
||||
})
|
||||
.toThrow(Error);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,12 +79,14 @@ describe('security issues', function() {
|
||||
var template = Handlebars.compile('{{helperMissing}}');
|
||||
template({}, { allowCallsToHelperMissing: true });
|
||||
});
|
||||
|
||||
it('should not throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() {
|
||||
var template = Handlebars.compile(
|
||||
'{{#helperMissing}}{{/helperMissing}}'
|
||||
);
|
||||
template({}, { allowCallsToHelperMissing: true });
|
||||
});
|
||||
|
||||
it('should not throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function() {
|
||||
var functionCalls = [];
|
||||
var template = Handlebars.compile('{{blockHelperMissing "abc" .}}');
|
||||
@@ -123,6 +100,7 @@ describe('security issues', function() {
|
||||
);
|
||||
equals(functionCalls.length, 1);
|
||||
});
|
||||
|
||||
it('should not throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function() {
|
||||
var template = Handlebars.compile(
|
||||
'{{#blockHelperMissing true}}sdads{{/blockHelperMissing}}'
|
||||
|
||||
+6
-16
@@ -40,22 +40,12 @@ describe('spec', function() {
|
||||
/* eslint-enable no-eval */
|
||||
}
|
||||
it(name + ' - ' + test.name, function() {
|
||||
if (test.partials) {
|
||||
shouldCompileToWithPartials(
|
||||
test.template,
|
||||
[data, {}, test.partials, true],
|
||||
true,
|
||||
test.expected,
|
||||
test.desc + ' "' + test.template + '"'
|
||||
);
|
||||
} else {
|
||||
shouldCompileTo(
|
||||
test.template,
|
||||
[data, {}, {}, true],
|
||||
test.expected,
|
||||
test.desc + ' "' + test.template + '"'
|
||||
);
|
||||
}
|
||||
expectTemplate(test.template)
|
||||
.withInput(data)
|
||||
.withPartials(test.partials || {})
|
||||
.withCompileOptions({ compat: true })
|
||||
.withMessage(test.desc + ' "' + test.template + '"')
|
||||
.toCompileTo(test.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+95
-161
@@ -3,161 +3,107 @@ var Exception = Handlebars.Exception;
|
||||
describe('strict', function() {
|
||||
describe('strict mode', function() {
|
||||
it('should error on missing property lookup', function() {
|
||||
shouldThrow(
|
||||
function() {
|
||||
var template = CompilerContext.compile('{{hello}}', { strict: true });
|
||||
|
||||
template({});
|
||||
},
|
||||
Exception,
|
||||
/"hello" not defined in/
|
||||
);
|
||||
expectTemplate('{{hello}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.toThrow(Exception, /"hello" not defined in/);
|
||||
});
|
||||
|
||||
it('should error on missing child', function() {
|
||||
var template = CompilerContext.compile('{{hello.bar}}', { strict: true });
|
||||
equals(template({ hello: { bar: 'foo' } }), 'foo');
|
||||
expectTemplate('{{hello.bar}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.withInput({ hello: { bar: 'foo' } })
|
||||
.toCompileTo('foo');
|
||||
|
||||
shouldThrow(
|
||||
function() {
|
||||
template({ hello: {} });
|
||||
},
|
||||
Exception,
|
||||
/"bar" not defined in/
|
||||
);
|
||||
expectTemplate('{{hello.bar}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.withInput({ hello: {} })
|
||||
.toThrow(Exception, /"bar" not defined in/);
|
||||
});
|
||||
|
||||
it('should handle explicit undefined', function() {
|
||||
var template = CompilerContext.compile('{{hello.bar}}', { strict: true });
|
||||
|
||||
equals(template({ hello: { bar: undefined } }), '');
|
||||
expectTemplate('{{hello.bar}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.withInput({ hello: { bar: undefined } })
|
||||
.toCompileTo('');
|
||||
});
|
||||
|
||||
it('should error on missing property lookup in known helpers mode', function() {
|
||||
shouldThrow(
|
||||
function() {
|
||||
var template = CompilerContext.compile('{{hello}}', {
|
||||
strict: true,
|
||||
knownHelpersOnly: true
|
||||
});
|
||||
|
||||
template({});
|
||||
},
|
||||
Exception,
|
||||
/"hello" not defined in/
|
||||
);
|
||||
expectTemplate('{{hello}}')
|
||||
.withCompileOptions({
|
||||
strict: true,
|
||||
knownHelpersOnly: true
|
||||
})
|
||||
.toThrow(Exception, /"hello" not defined in/);
|
||||
});
|
||||
it('should error on missing context', function() {
|
||||
shouldThrow(function() {
|
||||
var template = CompilerContext.compile('{{hello}}', { strict: true });
|
||||
|
||||
template();
|
||||
}, Error);
|
||||
it('should error on missing context', function() {
|
||||
expectTemplate('{{hello}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.toThrow(Error);
|
||||
});
|
||||
|
||||
it('should error on missing data lookup', function() {
|
||||
var template = CompilerContext.compile('{{@hello}}', { strict: true });
|
||||
equals(template(undefined, { data: { hello: 'foo' } }), 'foo');
|
||||
var xt = expectTemplate('{{@hello}}').withCompileOptions({
|
||||
strict: true
|
||||
});
|
||||
|
||||
shouldThrow(function() {
|
||||
template();
|
||||
}, Error);
|
||||
xt.toThrow(Error);
|
||||
|
||||
xt.withRuntimeOptions({ data: { hello: 'foo' } }).toCompileTo('foo');
|
||||
});
|
||||
|
||||
it('should not run helperMissing for helper calls', function() {
|
||||
shouldThrow(
|
||||
function() {
|
||||
var template = CompilerContext.compile('{{hello foo}}', {
|
||||
strict: true
|
||||
});
|
||||
expectTemplate('{{hello foo}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.withInput({ foo: true })
|
||||
.toThrow(Exception, /"hello" not defined in/);
|
||||
|
||||
template({ foo: true });
|
||||
},
|
||||
Exception,
|
||||
/"hello" not defined in/
|
||||
);
|
||||
|
||||
shouldThrow(
|
||||
function() {
|
||||
var template = CompilerContext.compile('{{#hello foo}}{{/hello}}', {
|
||||
strict: true
|
||||
});
|
||||
|
||||
template({ foo: true });
|
||||
},
|
||||
Exception,
|
||||
/"hello" not defined in/
|
||||
);
|
||||
expectTemplate('{{#hello foo}}{{/hello}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.withInput({ foo: true })
|
||||
.toThrow(Exception, /"hello" not defined in/);
|
||||
});
|
||||
|
||||
it('should throw on ambiguous blocks', function() {
|
||||
shouldThrow(
|
||||
function() {
|
||||
var template = CompilerContext.compile('{{#hello}}{{/hello}}', {
|
||||
strict: true
|
||||
});
|
||||
expectTemplate('{{#hello}}{{/hello}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.toThrow(Exception, /"hello" not defined in/);
|
||||
|
||||
template({});
|
||||
},
|
||||
Exception,
|
||||
/"hello" not defined in/
|
||||
);
|
||||
expectTemplate('{{^hello}}{{/hello}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.toThrow(Exception, /"hello" not defined in/);
|
||||
|
||||
shouldThrow(
|
||||
function() {
|
||||
var template = CompilerContext.compile('{{^hello}}{{/hello}}', {
|
||||
strict: true
|
||||
});
|
||||
|
||||
template({});
|
||||
},
|
||||
Exception,
|
||||
/"hello" not defined in/
|
||||
);
|
||||
|
||||
shouldThrow(
|
||||
function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#hello.bar}}{{/hello.bar}}',
|
||||
{ strict: true }
|
||||
);
|
||||
|
||||
template({ hello: {} });
|
||||
},
|
||||
Exception,
|
||||
/"bar" not defined in/
|
||||
);
|
||||
expectTemplate('{{#hello.bar}}{{/hello.bar}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.withInput({ hello: {} })
|
||||
.toThrow(Exception, /"bar" not defined in/);
|
||||
});
|
||||
|
||||
it('should allow undefined parameters when passed to helpers', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#unless foo}}success{{/unless}}',
|
||||
{ strict: true }
|
||||
);
|
||||
equals(template({}), 'success');
|
||||
expectTemplate('{{#unless foo}}success{{/unless}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should allow undefined hash when passed to helpers', function() {
|
||||
var template = CompilerContext.compile('{{helper value=@foo}}', {
|
||||
strict: true
|
||||
});
|
||||
var helpers = {
|
||||
helper: function(options) {
|
||||
equals('value' in options.hash, true);
|
||||
equals(options.hash.value, undefined);
|
||||
return 'success';
|
||||
}
|
||||
};
|
||||
equals(template({}, { helpers: helpers }), 'success');
|
||||
expectTemplate('{{helper value=@foo}}')
|
||||
.withCompileOptions({
|
||||
strict: true
|
||||
})
|
||||
.withHelpers({
|
||||
helper: function(options) {
|
||||
equals('value' in options.hash, true);
|
||||
equals(options.hash.value, undefined);
|
||||
return 'success';
|
||||
}
|
||||
})
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should show error location on missing property lookup', function() {
|
||||
shouldThrow(
|
||||
function() {
|
||||
var template = CompilerContext.compile('\n\n\n {{hello}}', {
|
||||
strict: true
|
||||
});
|
||||
template({});
|
||||
},
|
||||
Exception,
|
||||
'"hello" not defined in [object Object] - 4:5'
|
||||
);
|
||||
expectTemplate('\n\n\n {{hello}}')
|
||||
.withCompileOptions({ strict: true })
|
||||
.toThrow(Exception, '"hello" not defined in [object Object] - 4:5');
|
||||
});
|
||||
|
||||
it('should error contains correct location properties on missing property lookup', function() {
|
||||
@@ -177,54 +123,42 @@ describe('strict', function() {
|
||||
|
||||
describe('assume objects', function() {
|
||||
it('should ignore missing property', function() {
|
||||
var template = CompilerContext.compile('{{hello}}', {
|
||||
assumeObjects: true
|
||||
});
|
||||
|
||||
equal(template({}), '');
|
||||
expectTemplate('{{hello}}')
|
||||
.withCompileOptions({ assumeObjects: true })
|
||||
.toCompileTo('');
|
||||
});
|
||||
|
||||
it('should ignore missing child', function() {
|
||||
var template = CompilerContext.compile('{{hello.bar}}', {
|
||||
assumeObjects: true
|
||||
});
|
||||
|
||||
equal(template({ hello: {} }), '');
|
||||
expectTemplate('{{hello.bar}}')
|
||||
.withCompileOptions({ assumeObjects: true })
|
||||
.withInput({ hello: {} })
|
||||
.toCompileTo('');
|
||||
});
|
||||
|
||||
it('should error on missing object', function() {
|
||||
shouldThrow(function() {
|
||||
var template = CompilerContext.compile('{{hello.bar}}', {
|
||||
assumeObjects: true
|
||||
});
|
||||
|
||||
template({});
|
||||
}, Error);
|
||||
expectTemplate('{{hello.bar}}')
|
||||
.withCompileOptions({ assumeObjects: true })
|
||||
.toThrow(Error);
|
||||
});
|
||||
it('should error on missing context', function() {
|
||||
shouldThrow(function() {
|
||||
var template = CompilerContext.compile('{{hello}}', {
|
||||
assumeObjects: true
|
||||
});
|
||||
|
||||
template();
|
||||
}, Error);
|
||||
it('should error on missing context', function() {
|
||||
expectTemplate('{{hello}}')
|
||||
.withCompileOptions({ assumeObjects: true })
|
||||
.withInput(undefined)
|
||||
.toThrow(Error);
|
||||
});
|
||||
|
||||
it('should error on missing data lookup', function() {
|
||||
shouldThrow(function() {
|
||||
var template = CompilerContext.compile('{{@hello.bar}}', {
|
||||
assumeObjects: true
|
||||
});
|
||||
|
||||
template();
|
||||
}, Error);
|
||||
expectTemplate('{{@hello.bar}}')
|
||||
.withCompileOptions({ assumeObjects: true })
|
||||
.withInput(undefined)
|
||||
.toThrow(Error);
|
||||
});
|
||||
|
||||
it('should execute blockHelperMissing', function() {
|
||||
var template = CompilerContext.compile('{{^hello}}foo{{/hello}}', {
|
||||
assumeObjects: true
|
||||
});
|
||||
|
||||
equals(template({}), 'foo');
|
||||
expectTemplate('{{^hello}}foo{{/hello}}')
|
||||
.withCompileOptions({ assumeObjects: true })
|
||||
.toCompileTo('foo');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+152
-191
@@ -1,151 +1,117 @@
|
||||
describe('string params mode', function() {
|
||||
it('arguments to helpers can be retrieved from options hash in string form', function() {
|
||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {
|
||||
stringParams: true
|
||||
});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun) {
|
||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
|
||||
equals(
|
||||
result,
|
||||
'HELP ME MY BOSS is.a slave.driver',
|
||||
'String parameters output'
|
||||
);
|
||||
expectTemplate('{{wycats is.a slave.driver}}')
|
||||
.withCompileOptions({
|
||||
stringParams: true
|
||||
})
|
||||
.withHelpers({
|
||||
wycats: function(passiveVoice, noun) {
|
||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun;
|
||||
}
|
||||
})
|
||||
.withMessage('String parameters output')
|
||||
.toCompileTo('HELP ME MY BOSS is.a slave.driver');
|
||||
});
|
||||
|
||||
it('when using block form, arguments to helpers can be retrieved from options hash in string form', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#wycats is.a slave.driver}}help :({{/wycats}}',
|
||||
{ stringParams: true }
|
||||
);
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
noun +
|
||||
': ' +
|
||||
options.fn(this)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
|
||||
equals(
|
||||
result,
|
||||
'HELP ME MY BOSS is.a slave.driver: help :(',
|
||||
'String parameters output'
|
||||
);
|
||||
expectTemplate('{{#wycats is.a slave.driver}}help :({{/wycats}}')
|
||||
.withCompileOptions({
|
||||
stringParams: true
|
||||
})
|
||||
.withHelpers({
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
noun +
|
||||
': ' +
|
||||
options.fn(this)
|
||||
);
|
||||
}
|
||||
})
|
||||
.withMessage('String parameters output')
|
||||
.toCompileTo('HELP ME MY BOSS is.a slave.driver: help :(');
|
||||
});
|
||||
|
||||
it('when inside a block in String mode, .. passes the appropriate context in the options hash', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}',
|
||||
{ stringParams: true }
|
||||
);
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, options) {
|
||||
return (
|
||||
'STOP ME FROM READING HACKER NEWS I ' +
|
||||
options.contexts[0][desire] +
|
||||
' ' +
|
||||
noun
|
||||
);
|
||||
},
|
||||
|
||||
with: function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{
|
||||
expectTemplate('{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}')
|
||||
.withCompileOptions({
|
||||
stringParams: true
|
||||
})
|
||||
.withHelpers({
|
||||
tomdale: function(desire, noun, options) {
|
||||
return (
|
||||
'STOP ME FROM READING HACKER NEWS I ' +
|
||||
options.contexts[0][desire] +
|
||||
' ' +
|
||||
noun
|
||||
);
|
||||
},
|
||||
with: function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
}
|
||||
})
|
||||
.withInput({
|
||||
dale: {},
|
||||
|
||||
need: 'need-a'
|
||||
},
|
||||
{ helpers: helpers }
|
||||
);
|
||||
|
||||
equals(
|
||||
result,
|
||||
'STOP ME FROM READING HACKER NEWS I need-a dad.joke',
|
||||
'Proper context variable output'
|
||||
);
|
||||
})
|
||||
.withMessage('Proper context variable output')
|
||||
.toCompileTo('STOP ME FROM READING HACKER NEWS I need-a dad.joke');
|
||||
});
|
||||
|
||||
it('information about the types is passed along', function() {
|
||||
var template = CompilerContext.compile(
|
||||
"{{tomdale 'need' dad.joke true false}}",
|
||||
{ stringParams: true }
|
||||
);
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, trueBool, falseBool, options) {
|
||||
equal(options.types[0], 'StringLiteral', 'the string type is passed');
|
||||
equal(
|
||||
options.types[1],
|
||||
'PathExpression',
|
||||
'the expression type is passed'
|
||||
);
|
||||
equal(
|
||||
options.types[2],
|
||||
'BooleanLiteral',
|
||||
'the expression type is passed'
|
||||
);
|
||||
equal(desire, 'need', 'the string form is passed for strings');
|
||||
equal(noun, 'dad.joke', 'the string form is passed for expressions');
|
||||
equal(trueBool, true, 'raw booleans are passed through');
|
||||
equal(falseBool, false, 'raw booleans are passed through');
|
||||
return 'Helper called';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equal(result, 'Helper called');
|
||||
expectTemplate("{{tomdale 'need' dad.joke true false}}")
|
||||
.withCompileOptions({
|
||||
stringParams: true
|
||||
})
|
||||
.withHelpers({
|
||||
tomdale: function(desire, noun, trueBool, falseBool, options) {
|
||||
equal(options.types[0], 'StringLiteral', 'the string type is passed');
|
||||
equal(
|
||||
options.types[1],
|
||||
'PathExpression',
|
||||
'the expression type is passed'
|
||||
);
|
||||
equal(
|
||||
options.types[2],
|
||||
'BooleanLiteral',
|
||||
'the expression type is passed'
|
||||
);
|
||||
equal(desire, 'need', 'the string form is passed for strings');
|
||||
equal(noun, 'dad.joke', 'the string form is passed for expressions');
|
||||
equal(trueBool, true, 'raw booleans are passed through');
|
||||
equal(falseBool, false, 'raw booleans are passed through');
|
||||
return 'Helper called';
|
||||
}
|
||||
})
|
||||
.toCompileTo('Helper called');
|
||||
});
|
||||
|
||||
it('hash parameters get type information', function() {
|
||||
var template = CompilerContext.compile(
|
||||
"{{tomdale he.says desire='need' noun=dad.joke bool=true}}",
|
||||
{ stringParams: true }
|
||||
);
|
||||
expectTemplate("{{tomdale he.says desire='need' noun=dad.joke bool=true}}")
|
||||
.withCompileOptions({
|
||||
stringParams: true
|
||||
})
|
||||
.withHelpers({
|
||||
tomdale: function(exclamation, options) {
|
||||
equal(exclamation, 'he.says');
|
||||
equal(options.types[0], 'PathExpression');
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(exclamation, options) {
|
||||
equal(exclamation, 'he.says');
|
||||
equal(options.types[0], 'PathExpression');
|
||||
|
||||
equal(options.hashTypes.desire, 'StringLiteral');
|
||||
equal(options.hashTypes.noun, 'PathExpression');
|
||||
equal(options.hashTypes.bool, 'BooleanLiteral');
|
||||
equal(options.hash.desire, 'need');
|
||||
equal(options.hash.noun, 'dad.joke');
|
||||
equal(options.hash.bool, true);
|
||||
return 'Helper called';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equal(result, 'Helper called');
|
||||
equal(options.hashTypes.desire, 'StringLiteral');
|
||||
equal(options.hashTypes.noun, 'PathExpression');
|
||||
equal(options.hashTypes.bool, 'BooleanLiteral');
|
||||
equal(options.hash.desire, 'need');
|
||||
equal(options.hash.noun, 'dad.joke');
|
||||
equal(options.hash.bool, true);
|
||||
return 'Helper called';
|
||||
}
|
||||
})
|
||||
.toCompileTo('Helper called');
|
||||
});
|
||||
|
||||
it('hash parameters get context information', function() {
|
||||
var template = CompilerContext.compile(
|
||||
"{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}",
|
||||
{ stringParams: true }
|
||||
);
|
||||
|
||||
var context = { dale: {} };
|
||||
|
||||
var helpers = {
|
||||
@@ -165,82 +131,77 @@ describe('string params mode', function() {
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(context, { helpers: helpers });
|
||||
equal(result, 'Helper called');
|
||||
expectTemplate(
|
||||
"{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}"
|
||||
)
|
||||
.withCompileOptions({ stringParams: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput(context)
|
||||
.toCompileTo('Helper called');
|
||||
});
|
||||
|
||||
it('when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}',
|
||||
{ stringParams: true }
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}'
|
||||
)
|
||||
.withCompileOptions({
|
||||
stringParams: true
|
||||
})
|
||||
.withHelpers({
|
||||
tomdale: function(desire, noun, options) {
|
||||
return (
|
||||
'STOP ME FROM READING HACKER NEWS I ' +
|
||||
options.contexts[0][desire] +
|
||||
' ' +
|
||||
noun +
|
||||
' ' +
|
||||
options.fn(this)
|
||||
);
|
||||
},
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, options) {
|
||||
return (
|
||||
'STOP ME FROM READING HACKER NEWS I ' +
|
||||
options.contexts[0][desire] +
|
||||
' ' +
|
||||
noun +
|
||||
' ' +
|
||||
options.fn(this)
|
||||
);
|
||||
},
|
||||
|
||||
with: function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{
|
||||
with: function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
}
|
||||
})
|
||||
.withInput({
|
||||
dale: {},
|
||||
|
||||
need: 'need-a'
|
||||
},
|
||||
{ helpers: helpers }
|
||||
);
|
||||
|
||||
equals(
|
||||
result,
|
||||
'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot',
|
||||
'Proper context variable output'
|
||||
);
|
||||
})
|
||||
.withMessage('Proper context variable output')
|
||||
.toCompileTo('STOP ME FROM READING HACKER NEWS I need-a dad.joke wot');
|
||||
});
|
||||
|
||||
it('with nested block ambiguous', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}',
|
||||
{ stringParams: true }
|
||||
);
|
||||
|
||||
var helpers = {
|
||||
with: function() {
|
||||
return 'WITH';
|
||||
},
|
||||
view: function() {
|
||||
return 'VIEW';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equals(result, 'WITH');
|
||||
expectTemplate(
|
||||
'{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}'
|
||||
)
|
||||
.withCompileOptions({
|
||||
stringParams: true
|
||||
})
|
||||
.withHelpers({
|
||||
with: function() {
|
||||
return 'WITH';
|
||||
},
|
||||
view: function() {
|
||||
return 'VIEW';
|
||||
}
|
||||
})
|
||||
.toCompileTo('WITH');
|
||||
});
|
||||
|
||||
it('should handle DATA', function() {
|
||||
var template = CompilerContext.compile('{{foo @bar}}', {
|
||||
stringParams: true
|
||||
});
|
||||
|
||||
var helpers = {
|
||||
foo: function(bar, options) {
|
||||
equal(bar, '@bar');
|
||||
equal(options.types[0], 'PathExpression');
|
||||
return 'Foo!';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equal(result, 'Foo!');
|
||||
expectTemplate('{{foo @bar}}')
|
||||
.withCompileOptions({
|
||||
stringParams: true
|
||||
})
|
||||
.withHelpers({
|
||||
foo: function(bar, options) {
|
||||
equal(bar, '@bar');
|
||||
equal(options.types[0], 'PathExpression');
|
||||
return 'Foo!';
|
||||
}
|
||||
})
|
||||
.toCompileTo('Foo!');
|
||||
});
|
||||
});
|
||||
|
||||
+212
-226
@@ -1,61 +1,57 @@
|
||||
describe('subexpressions', function() {
|
||||
it('arg-less helper', function() {
|
||||
var string = '{{foo (bar)}}!';
|
||||
var context = {};
|
||||
var helpers = {
|
||||
foo: function(val) {
|
||||
return val + val;
|
||||
},
|
||||
bar: function() {
|
||||
return 'LOL';
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], 'LOLLOL!');
|
||||
expectTemplate('{{foo (bar)}}!')
|
||||
.withHelpers({
|
||||
foo: function(val) {
|
||||
return val + val;
|
||||
},
|
||||
bar: function() {
|
||||
return 'LOL';
|
||||
}
|
||||
})
|
||||
.toCompileTo('LOLLOL!');
|
||||
});
|
||||
|
||||
it('helper w args', function() {
|
||||
var string = '{{blog (equal a b)}}';
|
||||
|
||||
var context = { bar: 'LOL' };
|
||||
var helpers = {
|
||||
blog: function(val) {
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], 'val is true');
|
||||
expectTemplate('{{blog (equal a b)}}')
|
||||
.withInput({ bar: 'LOL' })
|
||||
.withHelpers({
|
||||
blog: function(val) {
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
})
|
||||
.toCompileTo('val is true');
|
||||
});
|
||||
|
||||
it('mixed paths and helpers', function() {
|
||||
var string = '{{blog baz.bat (equal a b) baz.bar}}';
|
||||
|
||||
var context = { bar: 'LOL', baz: { bat: 'foo!', bar: 'bar!' } };
|
||||
var helpers = {
|
||||
blog: function(val, that, theOther) {
|
||||
return 'val is ' + val + ', ' + that + ' and ' + theOther;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], 'val is foo!, true and bar!');
|
||||
expectTemplate('{{blog baz.bat (equal a b) baz.bar}}')
|
||||
.withInput({ bar: 'LOL', baz: { bat: 'foo!', bar: 'bar!' } })
|
||||
.withHelpers({
|
||||
blog: function(val, that, theOther) {
|
||||
return 'val is ' + val + ', ' + that + ' and ' + theOther;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
})
|
||||
.toCompileTo('val is foo!, true and bar!');
|
||||
});
|
||||
|
||||
it('supports much nesting', function() {
|
||||
var string = '{{blog (equal (equal true true) true)}}';
|
||||
|
||||
var context = { bar: 'LOL' };
|
||||
var helpers = {
|
||||
blog: function(val) {
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], 'val is true');
|
||||
expectTemplate('{{blog (equal (equal true true) true)}}')
|
||||
.withInput({ bar: 'LOL' })
|
||||
.withHelpers({
|
||||
blog: function(val) {
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
})
|
||||
.toCompileTo('val is true');
|
||||
});
|
||||
|
||||
it('GH-800 : Complex subexpressions', function() {
|
||||
@@ -69,20 +65,33 @@ describe('subexpressions', function() {
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
"{{dash 'abc' (concat a b)}}",
|
||||
[context, helpers],
|
||||
'abc-ab'
|
||||
);
|
||||
shouldCompileTo('{{dash d (concat a b)}}', [context, helpers], 'd-ab');
|
||||
shouldCompileTo('{{dash c.c (concat a b)}}', [context, helpers], 'c-ab');
|
||||
shouldCompileTo('{{dash (concat a b) c.c}}', [context, helpers], 'ab-c');
|
||||
shouldCompileTo('{{dash (concat a e.e) c.c}}', [context, helpers], 'ae-c');
|
||||
expectTemplate("{{dash 'abc' (concat a b)}}")
|
||||
.withInput(context)
|
||||
.withHelpers(helpers)
|
||||
.toCompileTo('abc-ab');
|
||||
|
||||
expectTemplate('{{dash d (concat a b)}}')
|
||||
.withInput(context)
|
||||
.withHelpers(helpers)
|
||||
.toCompileTo('d-ab');
|
||||
|
||||
expectTemplate('{{dash c.c (concat a b)}}')
|
||||
.withInput(context)
|
||||
.withHelpers(helpers)
|
||||
.toCompileTo('c-ab');
|
||||
|
||||
expectTemplate('{{dash (concat a b) c.c}}')
|
||||
.withInput(context)
|
||||
.withHelpers(helpers)
|
||||
.toCompileTo('ab-c');
|
||||
|
||||
expectTemplate('{{dash (concat a e.e) c.c}}')
|
||||
.withInput(context)
|
||||
.withHelpers(helpers)
|
||||
.toCompileTo('ae-c');
|
||||
});
|
||||
|
||||
it('provides each nested helper invocation its own options hash', function() {
|
||||
var string = '{{equal (equal true true) true}}';
|
||||
|
||||
var lastOptions = null;
|
||||
var helpers = {
|
||||
equal: function(x, y, options) {
|
||||
@@ -93,200 +102,177 @@ describe('subexpressions', function() {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [{}, helpers], 'true');
|
||||
expectTemplate('{{equal (equal true true) true}}')
|
||||
.withHelpers(helpers)
|
||||
.toCompileTo('true');
|
||||
});
|
||||
|
||||
it('with hashes', function() {
|
||||
var string = "{{blog (equal (equal true true) true fun='yes')}}";
|
||||
|
||||
var context = { bar: 'LOL' };
|
||||
var helpers = {
|
||||
blog: function(val) {
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], 'val is true');
|
||||
expectTemplate("{{blog (equal (equal true true) true fun='yes')}}")
|
||||
.withInput({ bar: 'LOL' })
|
||||
.withHelpers({
|
||||
blog: function(val) {
|
||||
return 'val is ' + val;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
})
|
||||
.toCompileTo('val is true');
|
||||
});
|
||||
|
||||
it('as hashes', function() {
|
||||
var string = "{{blog fun=(equal (blog fun=1) 'val is 1')}}";
|
||||
|
||||
var helpers = {
|
||||
blog: function(options) {
|
||||
return 'val is ' + options.hash.fun;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [{}, helpers], 'val is true');
|
||||
expectTemplate("{{blog fun=(equal (blog fun=1) 'val is 1')}}")
|
||||
.withHelpers({
|
||||
blog: function(options) {
|
||||
return 'val is ' + options.hash.fun;
|
||||
},
|
||||
equal: function(x, y) {
|
||||
return x === y;
|
||||
}
|
||||
})
|
||||
.toCompileTo('val is true');
|
||||
});
|
||||
|
||||
it('multiple subexpressions in a hash', function() {
|
||||
var string =
|
||||
'{{input aria-label=(t "Name") placeholder=(t "Example User")}}';
|
||||
|
||||
var helpers = {
|
||||
input: function(options) {
|
||||
var hash = options.hash;
|
||||
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
|
||||
var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
|
||||
return new Handlebars.SafeString(
|
||||
'<input aria-label="' +
|
||||
ariaLabel +
|
||||
'" placeholder="' +
|
||||
placeholder +
|
||||
'" />'
|
||||
);
|
||||
},
|
||||
t: function(defaultString) {
|
||||
return new Handlebars.SafeString(defaultString);
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
string,
|
||||
[{}, helpers],
|
||||
'<input aria-label="Name" placeholder="Example User" />'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{input aria-label=(t "Name") placeholder=(t "Example User")}}'
|
||||
)
|
||||
.withHelpers({
|
||||
input: function(options) {
|
||||
var hash = options.hash;
|
||||
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
|
||||
var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
|
||||
return new Handlebars.SafeString(
|
||||
'<input aria-label="' +
|
||||
ariaLabel +
|
||||
'" placeholder="' +
|
||||
placeholder +
|
||||
'" />'
|
||||
);
|
||||
},
|
||||
t: function(defaultString) {
|
||||
return new Handlebars.SafeString(defaultString);
|
||||
}
|
||||
})
|
||||
.toCompileTo('<input aria-label="Name" placeholder="Example User" />');
|
||||
});
|
||||
|
||||
it('multiple subexpressions in a hash with context', function() {
|
||||
var string =
|
||||
'{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}';
|
||||
|
||||
var context = {
|
||||
item: {
|
||||
field: 'Name',
|
||||
placeholder: 'Example User'
|
||||
}
|
||||
};
|
||||
|
||||
var helpers = {
|
||||
input: function(options) {
|
||||
var hash = options.hash;
|
||||
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
|
||||
var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
|
||||
return new Handlebars.SafeString(
|
||||
'<input aria-label="' +
|
||||
ariaLabel +
|
||||
'" placeholder="' +
|
||||
placeholder +
|
||||
'" />'
|
||||
);
|
||||
},
|
||||
t: function(defaultString) {
|
||||
return new Handlebars.SafeString(defaultString);
|
||||
}
|
||||
};
|
||||
shouldCompileTo(
|
||||
string,
|
||||
[context, helpers],
|
||||
'<input aria-label="Name" placeholder="Example User" />'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}'
|
||||
)
|
||||
.withInput({
|
||||
item: {
|
||||
field: 'Name',
|
||||
placeholder: 'Example User'
|
||||
}
|
||||
})
|
||||
.withHelpers({
|
||||
input: function(options) {
|
||||
var hash = options.hash;
|
||||
var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']);
|
||||
var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder);
|
||||
return new Handlebars.SafeString(
|
||||
'<input aria-label="' +
|
||||
ariaLabel +
|
||||
'" placeholder="' +
|
||||
placeholder +
|
||||
'" />'
|
||||
);
|
||||
},
|
||||
t: function(defaultString) {
|
||||
return new Handlebars.SafeString(defaultString);
|
||||
}
|
||||
})
|
||||
.toCompileTo('<input aria-label="Name" placeholder="Example User" />');
|
||||
});
|
||||
|
||||
it('in string params mode,', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{snog (blorg foo x=y) yeah a=b}}',
|
||||
{ stringParams: true }
|
||||
);
|
||||
expectTemplate('{{snog (blorg foo x=y) yeah a=b}}')
|
||||
.withCompileOptions({ stringParams: true })
|
||||
.withHelpers({
|
||||
snog: function(a, b, options) {
|
||||
equals(a, 'foo');
|
||||
equals(
|
||||
options.types.length,
|
||||
2,
|
||||
'string params for outer helper processed correctly'
|
||||
);
|
||||
equals(
|
||||
options.types[0],
|
||||
'SubExpression',
|
||||
'string params for outer helper processed correctly'
|
||||
);
|
||||
equals(
|
||||
options.types[1],
|
||||
'PathExpression',
|
||||
'string params for outer helper processed correctly'
|
||||
);
|
||||
return a + b;
|
||||
},
|
||||
|
||||
var helpers = {
|
||||
snog: function(a, b, options) {
|
||||
equals(a, 'foo');
|
||||
equals(
|
||||
options.types.length,
|
||||
2,
|
||||
'string params for outer helper processed correctly'
|
||||
);
|
||||
equals(
|
||||
options.types[0],
|
||||
'SubExpression',
|
||||
'string params for outer helper processed correctly'
|
||||
);
|
||||
equals(
|
||||
options.types[1],
|
||||
'PathExpression',
|
||||
'string params for outer helper processed correctly'
|
||||
);
|
||||
return a + b;
|
||||
},
|
||||
|
||||
blorg: function(a, options) {
|
||||
equals(
|
||||
options.types.length,
|
||||
1,
|
||||
'string params for inner helper processed correctly'
|
||||
);
|
||||
equals(
|
||||
options.types[0],
|
||||
'PathExpression',
|
||||
'string params for inner helper processed correctly'
|
||||
);
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(
|
||||
{
|
||||
blorg: function(a, options) {
|
||||
equals(
|
||||
options.types.length,
|
||||
1,
|
||||
'string params for inner helper processed correctly'
|
||||
);
|
||||
equals(
|
||||
options.types[0],
|
||||
'PathExpression',
|
||||
'string params for inner helper processed correctly'
|
||||
);
|
||||
return a;
|
||||
}
|
||||
})
|
||||
.withInput({
|
||||
foo: {},
|
||||
yeah: {}
|
||||
},
|
||||
{ helpers: helpers }
|
||||
);
|
||||
|
||||
equals(result, 'fooyeah');
|
||||
})
|
||||
.toCompileTo('fooyeah');
|
||||
});
|
||||
|
||||
it('as hashes in string params mode', function() {
|
||||
var template = CompilerContext.compile('{{blog fun=(bork)}}', {
|
||||
stringParams: true
|
||||
});
|
||||
|
||||
var helpers = {
|
||||
blog: function(options) {
|
||||
equals(options.hashTypes.fun, 'SubExpression');
|
||||
return 'val is ' + options.hash.fun;
|
||||
},
|
||||
bork: function() {
|
||||
return 'BORK';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equals(result, 'val is BORK');
|
||||
expectTemplate('{{blog fun=(bork)}}')
|
||||
.withCompileOptions({ stringParams: true })
|
||||
.withHelpers({
|
||||
blog: function(options) {
|
||||
equals(options.hashTypes.fun, 'SubExpression');
|
||||
return 'val is ' + options.hash.fun;
|
||||
},
|
||||
bork: function() {
|
||||
return 'BORK';
|
||||
}
|
||||
})
|
||||
.toCompileTo('val is BORK');
|
||||
});
|
||||
|
||||
it('subexpression functions on the context', function() {
|
||||
var string = '{{foo (bar)}}!';
|
||||
var context = {
|
||||
bar: function() {
|
||||
return 'LOL';
|
||||
}
|
||||
};
|
||||
var helpers = {
|
||||
foo: function(val) {
|
||||
return val + val;
|
||||
}
|
||||
};
|
||||
shouldCompileTo(string, [context, helpers], 'LOLLOL!');
|
||||
expectTemplate('{{foo (bar)}}!')
|
||||
.withInput({
|
||||
bar: function() {
|
||||
return 'LOL';
|
||||
}
|
||||
})
|
||||
.withHelpers({
|
||||
foo: function(val) {
|
||||
return val + val;
|
||||
}
|
||||
})
|
||||
.toCompileTo('LOLLOL!');
|
||||
});
|
||||
|
||||
it("subexpressions can't just be property lookups", function() {
|
||||
var string = '{{foo (bar)}}!';
|
||||
var context = {
|
||||
bar: 'LOL'
|
||||
};
|
||||
var helpers = {
|
||||
foo: function(val) {
|
||||
return val + val;
|
||||
}
|
||||
};
|
||||
shouldThrow(function() {
|
||||
shouldCompileTo(string, [context, helpers], 'LOLLOL!');
|
||||
});
|
||||
expectTemplate('{{foo (bar)}}!')
|
||||
.withInput({
|
||||
bar: 'LOL'
|
||||
})
|
||||
.withHelpers({
|
||||
foo: function(val) {
|
||||
return val + val;
|
||||
}
|
||||
})
|
||||
.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
+213
-279
@@ -5,216 +5,184 @@ describe('track ids', function() {
|
||||
});
|
||||
|
||||
it('should not include anything without the flag', function() {
|
||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}');
|
||||
expectTemplate('{{wycats is.a slave.driver}}')
|
||||
.withHelpers({
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids, undefined);
|
||||
equal(options.hashIds, undefined);
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids, undefined);
|
||||
equal(options.hashIds, undefined);
|
||||
|
||||
return 'success';
|
||||
}
|
||||
};
|
||||
|
||||
equals(template({}, { helpers: helpers }), 'success');
|
||||
return 'success';
|
||||
}
|
||||
})
|
||||
.toCompileTo('success');
|
||||
});
|
||||
|
||||
it('should include argument ids', function() {
|
||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {
|
||||
trackIds: true
|
||||
});
|
||||
expectTemplate('{{wycats is.a slave.driver}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers({
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], 'is.a');
|
||||
equal(options.ids[1], 'slave.driver');
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], 'is.a');
|
||||
equal(options.ids[1], 'slave.driver');
|
||||
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.ids[0] +
|
||||
':' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
options.ids[1] +
|
||||
':' +
|
||||
noun
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
equals(
|
||||
template(context, { helpers: helpers }),
|
||||
'HELP ME MY BOSS is.a:foo slave.driver:bar'
|
||||
);
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.ids[0] +
|
||||
':' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
options.ids[1] +
|
||||
':' +
|
||||
noun
|
||||
);
|
||||
}
|
||||
})
|
||||
.withInput(context)
|
||||
.toCompileTo('HELP ME MY BOSS is.a:foo slave.driver:bar');
|
||||
});
|
||||
|
||||
it('should include hash ids', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{wycats bat=is.a baz=slave.driver}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
expectTemplate('{{wycats bat=is.a baz=slave.driver}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers({
|
||||
wycats: function(options) {
|
||||
equal(options.hashIds.bat, 'is.a');
|
||||
equal(options.hashIds.baz, 'slave.driver');
|
||||
|
||||
var helpers = {
|
||||
wycats: function(options) {
|
||||
equal(options.hashIds.bat, 'is.a');
|
||||
equal(options.hashIds.baz, 'slave.driver');
|
||||
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.hashIds.bat +
|
||||
':' +
|
||||
options.hash.bat +
|
||||
' ' +
|
||||
options.hashIds.baz +
|
||||
':' +
|
||||
options.hash.baz
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
equals(
|
||||
template(context, { helpers: helpers }),
|
||||
'HELP ME MY BOSS is.a:foo slave.driver:bar'
|
||||
);
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.hashIds.bat +
|
||||
':' +
|
||||
options.hash.bat +
|
||||
' ' +
|
||||
options.hashIds.baz +
|
||||
':' +
|
||||
options.hash.baz
|
||||
);
|
||||
}
|
||||
})
|
||||
.withInput(context)
|
||||
.toCompileTo('HELP ME MY BOSS is.a:foo slave.driver:bar');
|
||||
});
|
||||
|
||||
it('should note ../ and ./ references', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{wycats ./is.a ../slave.driver this.is.a this}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
expectTemplate('{{wycats ./is.a ../slave.driver this.is.a this}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers({
|
||||
wycats: function(passiveVoice, noun, thiz, thiz2, options) {
|
||||
equal(options.ids[0], 'is.a');
|
||||
equal(options.ids[1], '../slave.driver');
|
||||
equal(options.ids[2], 'is.a');
|
||||
equal(options.ids[3], '');
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, thiz, thiz2, options) {
|
||||
equal(options.ids[0], 'is.a');
|
||||
equal(options.ids[1], '../slave.driver');
|
||||
equal(options.ids[2], 'is.a');
|
||||
equal(options.ids[3], '');
|
||||
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.ids[0] +
|
||||
':' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
options.ids[1] +
|
||||
':' +
|
||||
noun
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
equals(
|
||||
template(context, { helpers: helpers }),
|
||||
'HELP ME MY BOSS is.a:foo ../slave.driver:undefined'
|
||||
);
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.ids[0] +
|
||||
':' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
options.ids[1] +
|
||||
':' +
|
||||
noun
|
||||
);
|
||||
}
|
||||
})
|
||||
.withInput(context)
|
||||
.toCompileTo('HELP ME MY BOSS is.a:foo ../slave.driver:undefined');
|
||||
});
|
||||
|
||||
it('should note @data references', function() {
|
||||
var template = CompilerContext.compile('{{wycats @is.a @slave.driver}}', {
|
||||
trackIds: true
|
||||
});
|
||||
expectTemplate('{{wycats @is.a @slave.driver}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers({
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], '@is.a');
|
||||
equal(options.ids[1], '@slave.driver');
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], '@is.a');
|
||||
equal(options.ids[1], '@slave.driver');
|
||||
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.ids[0] +
|
||||
':' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
options.ids[1] +
|
||||
':' +
|
||||
noun
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
equals(
|
||||
template({}, { helpers: helpers, data: context }),
|
||||
'HELP ME MY BOSS @is.a:foo @slave.driver:bar'
|
||||
);
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.ids[0] +
|
||||
':' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
options.ids[1] +
|
||||
':' +
|
||||
noun
|
||||
);
|
||||
}
|
||||
})
|
||||
.withRuntimeOptions({ data: context })
|
||||
.toCompileTo('HELP ME MY BOSS @is.a:foo @slave.driver:bar');
|
||||
});
|
||||
|
||||
it('should return null for constants', function() {
|
||||
var template = CompilerContext.compile('{{wycats 1 "foo" key=false}}', {
|
||||
trackIds: true
|
||||
});
|
||||
expectTemplate('{{wycats 1 "foo" key=false}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers({
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], null);
|
||||
equal(options.ids[1], null);
|
||||
equal(options.hashIds.key, null);
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], null);
|
||||
equal(options.ids[1], null);
|
||||
equal(options.hashIds.key, null);
|
||||
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
noun +
|
||||
' ' +
|
||||
options.hash.key
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
equals(
|
||||
template(context, { helpers: helpers }),
|
||||
'HELP ME MY BOSS 1 foo false'
|
||||
);
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
noun +
|
||||
' ' +
|
||||
options.hash.key
|
||||
);
|
||||
}
|
||||
})
|
||||
.withInput(context)
|
||||
.toCompileTo('HELP ME MY BOSS 1 foo false');
|
||||
});
|
||||
|
||||
it('should return true for subexpressions', function() {
|
||||
var template = CompilerContext.compile('{{wycats (sub)}}', {
|
||||
trackIds: true
|
||||
});
|
||||
expectTemplate('{{wycats (sub)}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers({
|
||||
sub: function() {
|
||||
return 1;
|
||||
},
|
||||
wycats: function(passiveVoice, options) {
|
||||
equal(options.ids[0], true);
|
||||
|
||||
var helpers = {
|
||||
sub: function() {
|
||||
return 1;
|
||||
},
|
||||
wycats: function(passiveVoice, options) {
|
||||
equal(options.ids[0], true);
|
||||
|
||||
return 'HELP ME MY BOSS ' + passiveVoice;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template(context, { helpers: helpers }), 'HELP ME MY BOSS 1');
|
||||
return 'HELP ME MY BOSS ' + passiveVoice;
|
||||
}
|
||||
})
|
||||
.withInput(context)
|
||||
.toCompileTo('HELP ME MY BOSS 1');
|
||||
});
|
||||
|
||||
it('should use block param paths', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#doIt as |is|}}{{wycats is.a slave.driver is}}{{/doIt}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
expectTemplate('{{#doIt as |is|}}{{wycats is.a slave.driver is}}{{/doIt}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers({
|
||||
doIt: function(options) {
|
||||
var blockParams = [this.is];
|
||||
blockParams.path = ['zomg'];
|
||||
return options.fn(this, { blockParams: blockParams });
|
||||
},
|
||||
wycats: function(passiveVoice, noun, blah, options) {
|
||||
equal(options.ids[0], 'zomg.a');
|
||||
equal(options.ids[1], 'slave.driver');
|
||||
equal(options.ids[2], 'zomg');
|
||||
|
||||
var helpers = {
|
||||
doIt: function(options) {
|
||||
var blockParams = [this.is];
|
||||
blockParams.path = ['zomg'];
|
||||
return options.fn(this, { blockParams: blockParams });
|
||||
},
|
||||
wycats: function(passiveVoice, noun, blah, options) {
|
||||
equal(options.ids[0], 'zomg.a');
|
||||
equal(options.ids[1], 'slave.driver');
|
||||
equal(options.ids[2], 'zomg');
|
||||
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.ids[0] +
|
||||
':' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
options.ids[1] +
|
||||
':' +
|
||||
noun
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
equals(
|
||||
template(context, { helpers: helpers }),
|
||||
'HELP ME MY BOSS zomg.a:foo slave.driver:bar'
|
||||
);
|
||||
return (
|
||||
'HELP ME MY BOSS ' +
|
||||
options.ids[0] +
|
||||
':' +
|
||||
passiveVoice +
|
||||
' ' +
|
||||
options.ids[1] +
|
||||
':' +
|
||||
noun
|
||||
);
|
||||
}
|
||||
})
|
||||
.withInput(context)
|
||||
.toCompileTo('HELP ME MY BOSS zomg.a:foo slave.driver:bar');
|
||||
});
|
||||
|
||||
describe('builtin helpers', function() {
|
||||
@@ -229,119 +197,85 @@ describe('track ids', function() {
|
||||
|
||||
describe('#each', function() {
|
||||
it('should track contextPath for arrays', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#each array}}{{wycats name}}{{/each}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template(
|
||||
{ array: [{ name: 'foo' }, { name: 'bar' }] },
|
||||
{ helpers: helpers }
|
||||
),
|
||||
'foo:array.0\nbar:array.1\n'
|
||||
);
|
||||
expectTemplate('{{#each array}}{{wycats name}}{{/each}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ array: [{ name: 'foo' }, { name: 'bar' }] })
|
||||
.toCompileTo('foo:array.0\nbar:array.1\n');
|
||||
});
|
||||
|
||||
it('should track contextPath for keys', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#each object}}{{wycats name}}{{/each}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template(
|
||||
{ object: { foo: { name: 'foo' }, bar: { name: 'bar' } } },
|
||||
{ helpers: helpers }
|
||||
),
|
||||
'foo:object.foo\nbar:object.bar\n'
|
||||
);
|
||||
expectTemplate('{{#each object}}{{wycats name}}{{/each}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ object: { foo: { name: 'foo' }, bar: { name: 'bar' } } })
|
||||
.toCompileTo('foo:object.foo\nbar:object.bar\n');
|
||||
});
|
||||
|
||||
it('should handle nesting', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#each .}}{{#each .}}{{wycats name}}{{/each}}{{/each}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template(
|
||||
{ array: [{ name: 'foo' }, { name: 'bar' }] },
|
||||
{ helpers: helpers }
|
||||
),
|
||||
'foo:.array..0\nbar:.array..1\n'
|
||||
);
|
||||
expectTemplate(
|
||||
'{{#each .}}{{#each .}}{{wycats name}}{{/each}}{{/each}}'
|
||||
)
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ array: [{ name: 'foo' }, { name: 'bar' }] })
|
||||
.toCompileTo('foo:.array..0\nbar:.array..1\n');
|
||||
});
|
||||
it('should handle block params', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#each array as |value|}}{{blockParams value.name}}{{/each}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template(
|
||||
{ array: [{ name: 'foo' }, { name: 'bar' }] },
|
||||
{ helpers: helpers }
|
||||
),
|
||||
'foo:array.0.name\nbar:array.1.name\n'
|
||||
);
|
||||
it('should handle block params', function() {
|
||||
expectTemplate(
|
||||
'{{#each array as |value|}}{{blockParams value.name}}{{/each}}'
|
||||
)
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ array: [{ name: 'foo' }, { name: 'bar' }] })
|
||||
.toCompileTo('foo:array.0.name\nbar:array.1.name\n');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#with', function() {
|
||||
it('should track contextPath', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#with field}}{{wycats name}}{{/with}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template({ field: { name: 'foo' } }, { helpers: helpers }),
|
||||
'foo:field\n'
|
||||
);
|
||||
expectTemplate('{{#with field}}{{wycats name}}{{/with}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ field: { name: 'foo' } })
|
||||
.toCompileTo('foo:field\n');
|
||||
});
|
||||
it('should handle nesting', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#with bat}}{{#with field}}{{wycats name}}{{/with}}{{/with}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template({ bat: { field: { name: 'foo' } } }, { helpers: helpers }),
|
||||
'foo:bat.field\n'
|
||||
);
|
||||
it('should handle nesting', function() {
|
||||
expectTemplate(
|
||||
'{{#with bat}}{{#with field}}{{wycats name}}{{/with}}{{/with}}'
|
||||
)
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ bat: { field: { name: 'foo' } } })
|
||||
.toCompileTo('foo:bat.field\n');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#blockHelperMissing', function() {
|
||||
it('should track contextPath for arrays', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#field}}{{wycats name}}{{/field}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template({ field: [{ name: 'foo' }] }, { helpers: helpers }),
|
||||
'foo:field.0\n'
|
||||
);
|
||||
expectTemplate('{{#field}}{{wycats name}}{{/field}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ field: [{ name: 'foo' }] })
|
||||
.toCompileTo('foo:field.0\n');
|
||||
});
|
||||
|
||||
it('should track contextPath for keys', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#field}}{{wycats name}}{{/field}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template({ field: { name: 'foo' } }, { helpers: helpers }),
|
||||
'foo:field\n'
|
||||
);
|
||||
expectTemplate('{{#field}}{{wycats name}}{{/field}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ field: { name: 'foo' } })
|
||||
.toCompileTo('foo:field\n');
|
||||
});
|
||||
it('should handle nesting', function() {
|
||||
var template = CompilerContext.compile(
|
||||
'{{#bat}}{{#field}}{{wycats name}}{{/field}}{{/bat}}',
|
||||
{ trackIds: true }
|
||||
);
|
||||
|
||||
equals(
|
||||
template({ bat: { field: { name: 'foo' } } }, { helpers: helpers }),
|
||||
'foo:bat.field\n'
|
||||
);
|
||||
it('should handle nesting', function() {
|
||||
expectTemplate('{{#bat}}{{#field}}{{wycats name}}{{/field}}{{/bat}}')
|
||||
.withCompileOptions({ trackIds: true })
|
||||
.withHelpers(helpers)
|
||||
.withInput({ bat: { field: { name: 'foo' } } })
|
||||
.toCompileTo('foo:bat.field\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+3
-5
@@ -15,11 +15,9 @@ describe('utils', function() {
|
||||
it('it should not escape SafeString properties', function() {
|
||||
var name = new Handlebars.SafeString('<em>Sean O'Malley</em>');
|
||||
|
||||
shouldCompileTo(
|
||||
'{{name}}',
|
||||
[{ name: name }],
|
||||
'<em>Sean O'Malley</em>'
|
||||
);
|
||||
expectTemplate('{{name}}')
|
||||
.withInput({ name: name })
|
||||
.toCompileTo('<em>Sean O'Malley</em>');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+118
-87
@@ -2,125 +2,156 @@ describe('whitespace control', function() {
|
||||
it('should strip whitespace around mustache calls', function() {
|
||||
var hash = { foo: 'bar<' };
|
||||
|
||||
shouldCompileTo(' {{~foo~}} ', hash, 'bar<');
|
||||
shouldCompileTo(' {{~foo}} ', hash, 'bar< ');
|
||||
shouldCompileTo(' {{foo~}} ', hash, ' bar<');
|
||||
expectTemplate(' {{~foo~}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar<');
|
||||
|
||||
shouldCompileTo(' {{~&foo~}} ', hash, 'bar<');
|
||||
shouldCompileTo(' {{~{foo}~}} ', hash, 'bar<');
|
||||
expectTemplate(' {{~foo}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar< ');
|
||||
|
||||
shouldCompileTo('1\n{{foo~}} \n\n 23\n{{bar}}4', {}, '1\n23\n4');
|
||||
expectTemplate(' {{foo~}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo(' bar<');
|
||||
|
||||
expectTemplate(' {{~&foo~}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar<');
|
||||
|
||||
expectTemplate(' {{~{foo}~}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar<');
|
||||
|
||||
expectTemplate('1\n{{foo~}} \n\n 23\n{{bar}}4').toCompileTo('1\n23\n4');
|
||||
});
|
||||
|
||||
describe('blocks', function() {
|
||||
it('should strip whitespace around simple block calls', function() {
|
||||
var hash = { foo: 'bar<' };
|
||||
|
||||
shouldCompileTo(' {{~#if foo~}} bar {{~/if~}} ', hash, 'bar');
|
||||
shouldCompileTo(' {{#if foo~}} bar {{/if~}} ', hash, ' bar ');
|
||||
shouldCompileTo(' {{~#if foo}} bar {{~/if}} ', hash, ' bar ');
|
||||
shouldCompileTo(' {{#if foo}} bar {{/if}} ', hash, ' bar ');
|
||||
expectTemplate(' {{~#if foo~}} bar {{~/if~}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar');
|
||||
|
||||
shouldCompileTo(
|
||||
' \n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\n ',
|
||||
hash,
|
||||
'bar'
|
||||
);
|
||||
shouldCompileTo(
|
||||
' a\n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\na ',
|
||||
hash,
|
||||
' abara '
|
||||
);
|
||||
expectTemplate(' {{#if foo~}} bar {{/if~}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo(' bar ');
|
||||
|
||||
expectTemplate(' {{~#if foo}} bar {{~/if}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo(' bar ');
|
||||
|
||||
expectTemplate(' {{#if foo}} bar {{/if}} ')
|
||||
.withInput(hash)
|
||||
.toCompileTo(' bar ');
|
||||
|
||||
expectTemplate(' \n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\n ')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar');
|
||||
|
||||
expectTemplate(' a\n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\na ')
|
||||
.withInput(hash)
|
||||
.toCompileTo(' abara ');
|
||||
});
|
||||
|
||||
it('should strip whitespace around inverse block calls', function() {
|
||||
var hash = {};
|
||||
expectTemplate(' {{~^if foo~}} bar {{~/if~}} ').toCompileTo('bar');
|
||||
|
||||
shouldCompileTo(' {{~^if foo~}} bar {{~/if~}} ', hash, 'bar');
|
||||
shouldCompileTo(' {{^if foo~}} bar {{/if~}} ', hash, ' bar ');
|
||||
shouldCompileTo(' {{~^if foo}} bar {{~/if}} ', hash, ' bar ');
|
||||
shouldCompileTo(' {{^if foo}} bar {{/if}} ', hash, ' bar ');
|
||||
expectTemplate(' {{^if foo~}} bar {{/if~}} ').toCompileTo(' bar ');
|
||||
|
||||
shouldCompileTo(
|
||||
' \n\n{{~^if foo~}} \n\nbar \n\n{{~/if~}}\n\n ',
|
||||
hash,
|
||||
'bar'
|
||||
);
|
||||
expectTemplate(' {{~^if foo}} bar {{~/if}} ').toCompileTo(' bar ');
|
||||
|
||||
expectTemplate(' {{^if foo}} bar {{/if}} ').toCompileTo(' bar ');
|
||||
|
||||
expectTemplate(
|
||||
' \n\n{{~^if foo~}} \n\nbar \n\n{{~/if~}}\n\n '
|
||||
).toCompileTo('bar');
|
||||
});
|
||||
|
||||
it('should strip whitespace around complex block calls', function() {
|
||||
var hash = { foo: 'bar<' };
|
||||
|
||||
shouldCompileTo('{{#if foo~}} bar {{~^~}} baz {{~/if}}', hash, 'bar');
|
||||
shouldCompileTo('{{#if foo~}} bar {{^~}} baz {{/if}}', hash, 'bar ');
|
||||
shouldCompileTo('{{#if foo}} bar {{~^~}} baz {{~/if}}', hash, ' bar');
|
||||
shouldCompileTo('{{#if foo}} bar {{^~}} baz {{/if}}', hash, ' bar ');
|
||||
expectTemplate('{{#if foo~}} bar {{~^~}} baz {{~/if}}')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar');
|
||||
|
||||
shouldCompileTo('{{#if foo~}} bar {{~else~}} baz {{~/if}}', hash, 'bar');
|
||||
expectTemplate('{{#if foo~}} bar {{^~}} baz {{/if}}')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar ');
|
||||
|
||||
shouldCompileTo(
|
||||
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
|
||||
hash,
|
||||
'bar'
|
||||
);
|
||||
shouldCompileTo(
|
||||
'\n\n{{~#if foo~}} \n\n{{{foo}}} \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
|
||||
hash,
|
||||
'bar<'
|
||||
);
|
||||
expectTemplate('{{#if foo}} bar {{~^~}} baz {{~/if}}')
|
||||
.withInput(hash)
|
||||
.toCompileTo(' bar');
|
||||
|
||||
hash = {};
|
||||
expectTemplate('{{#if foo}} bar {{^~}} baz {{/if}}')
|
||||
.withInput(hash)
|
||||
.toCompileTo(' bar ');
|
||||
|
||||
shouldCompileTo('{{#if foo~}} bar {{~^~}} baz {{~/if}}', hash, 'baz');
|
||||
shouldCompileTo('{{#if foo}} bar {{~^~}} baz {{/if}}', hash, 'baz ');
|
||||
shouldCompileTo('{{#if foo~}} bar {{~^}} baz {{~/if}}', hash, ' baz');
|
||||
shouldCompileTo('{{#if foo~}} bar {{~^}} baz {{/if}}', hash, ' baz ');
|
||||
expectTemplate('{{#if foo~}} bar {{~else~}} baz {{~/if}}')
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar');
|
||||
|
||||
shouldCompileTo('{{#if foo~}} bar {{~else~}} baz {{~/if}}', hash, 'baz');
|
||||
expectTemplate(
|
||||
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n'
|
||||
)
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar');
|
||||
|
||||
shouldCompileTo(
|
||||
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
|
||||
hash,
|
||||
expectTemplate(
|
||||
'\n\n{{~#if foo~}} \n\n{{{foo}}} \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n'
|
||||
)
|
||||
.withInput(hash)
|
||||
.toCompileTo('bar<');
|
||||
|
||||
expectTemplate('{{#if foo~}} bar {{~^~}} baz {{~/if}}').toCompileTo(
|
||||
'baz'
|
||||
);
|
||||
|
||||
expectTemplate('{{#if foo}} bar {{~^~}} baz {{/if}}').toCompileTo('baz ');
|
||||
|
||||
expectTemplate('{{#if foo~}} bar {{~^}} baz {{~/if}}').toCompileTo(
|
||||
' baz'
|
||||
);
|
||||
|
||||
expectTemplate('{{#if foo~}} bar {{~^}} baz {{/if}}').toCompileTo(
|
||||
' baz '
|
||||
);
|
||||
|
||||
expectTemplate('{{#if foo~}} bar {{~else~}} baz {{~/if}}').toCompileTo(
|
||||
'baz'
|
||||
);
|
||||
|
||||
expectTemplate(
|
||||
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n'
|
||||
).toCompileTo('baz');
|
||||
});
|
||||
});
|
||||
|
||||
it('should strip whitespace around partials', function() {
|
||||
shouldCompileToWithPartials(
|
||||
'foo {{~> dude~}} ',
|
||||
[{}, {}, { dude: 'bar' }],
|
||||
true,
|
||||
'foobar'
|
||||
);
|
||||
shouldCompileToWithPartials(
|
||||
'foo {{> dude~}} ',
|
||||
[{}, {}, { dude: 'bar' }],
|
||||
true,
|
||||
'foo bar'
|
||||
);
|
||||
shouldCompileToWithPartials(
|
||||
'foo {{> dude}} ',
|
||||
[{}, {}, { dude: 'bar' }],
|
||||
true,
|
||||
'foo bar '
|
||||
);
|
||||
expectTemplate('foo {{~> dude~}} ')
|
||||
.withPartials({ dude: 'bar' })
|
||||
.toCompileTo('foobar');
|
||||
|
||||
shouldCompileToWithPartials(
|
||||
'foo\n {{~> dude}} ',
|
||||
[{}, {}, { dude: 'bar' }],
|
||||
true,
|
||||
'foobar'
|
||||
);
|
||||
shouldCompileToWithPartials(
|
||||
'foo\n {{> dude}} ',
|
||||
[{}, {}, { dude: 'bar' }],
|
||||
true,
|
||||
'foo\n bar'
|
||||
);
|
||||
expectTemplate('foo {{> dude~}} ')
|
||||
.withPartials({ dude: 'bar' })
|
||||
.toCompileTo('foo bar');
|
||||
|
||||
expectTemplate('foo {{> dude}} ')
|
||||
.withPartials({ dude: 'bar' })
|
||||
.toCompileTo('foo bar ');
|
||||
|
||||
expectTemplate('foo\n {{~> dude}} ')
|
||||
.withPartials({ dude: 'bar' })
|
||||
.toCompileTo('foobar');
|
||||
|
||||
expectTemplate('foo\n {{> dude}} ')
|
||||
.withPartials({ dude: 'bar' })
|
||||
.toCompileTo('foo\n bar');
|
||||
});
|
||||
|
||||
it('should only strip whitespace once', function() {
|
||||
var hash = { foo: 'bar' };
|
||||
|
||||
shouldCompileTo(' {{~foo~}} {{foo}} {{foo}} ', hash, 'barbar bar ');
|
||||
expectTemplate(' {{~foo~}} {{foo}} {{foo}} ')
|
||||
.withInput({ foo: 'bar' })
|
||||
.toCompileTo('barbar bar ');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user