f30b3ea329
This changes the call signature for the CommentNode constructor, which is a potentially breaking change for AST users. Fixes #866
229 lines
10 KiB
JavaScript
229 lines
10 KiB
JavaScript
/*global CompilerContext, Handlebars, beforeEach, shouldCompileTo */
|
|
global.handlebarsEnv = null;
|
|
|
|
beforeEach(function() {
|
|
global.handlebarsEnv = Handlebars.create();
|
|
});
|
|
|
|
describe("basic context", function() {
|
|
it("most basic", function() {
|
|
shouldCompileTo("{{foo}}", { foo: "foo" }, "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");
|
|
});
|
|
|
|
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");
|
|
});
|
|
|
|
it("compiling with an undefined context", function() {
|
|
shouldCompileTo("Goodbye\n{{cruel}}\n{{world.bar}}!", undefined, "Goodbye\n\n!");
|
|
|
|
shouldCompileTo("{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}", undefined, "Goodbye");
|
|
});
|
|
|
|
it("comments", function() {
|
|
shouldCompileTo("{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!",
|
|
{cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
|
|
"comments are ignored");
|
|
|
|
shouldCompileTo(' {{~! comment ~}} blah', {}, 'blah');
|
|
shouldCompileTo(' {{~!-- long-comment --~}} blah', {}, '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");
|
|
|
|
shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
|
|
"booleans do not show the contents when false");
|
|
});
|
|
|
|
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");
|
|
});
|
|
it('false', function() {
|
|
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');
|
|
|
|
shouldCompileTo('val1: {{{val1}}}, val2: {{{val2}}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false');
|
|
shouldCompileTo('val: {{{val1/val2}}}', {val1: {val2: false}}, 'val: false');
|
|
});
|
|
|
|
it("newlines", function() {
|
|
shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest");
|
|
shouldCompileTo("Alan's\rTest", {}, "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");
|
|
});
|
|
|
|
it("escaping expressions", function() {
|
|
shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>',
|
|
"expressions with 3 handlebars aren't escaped");
|
|
|
|
shouldCompileTo("{{&awesome}}", {awesome: "&\"\\<>"}, '&\"\\<>',
|
|
"expressions with {{& handlebars aren't escaped");
|
|
|
|
shouldCompileTo("{{awesome}}", {awesome: "&\"'`\\<>"}, '&"'`\\<>',
|
|
"by default expressions should be escaped");
|
|
|
|
shouldCompileTo("{{awesome}}", {awesome: "Escaped, <b> looks like: <b>"}, 'Escaped, <b> looks like: &lt;b&gt;',
|
|
"escaping should properly handle amperstands");
|
|
});
|
|
|
|
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");
|
|
});
|
|
|
|
it("functions", function() {
|
|
shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome",
|
|
"functions are called and render their output");
|
|
shouldCompileTo("{{awesome}}", {awesome: function() { return this.more; }, more: "More awesome"}, "More awesome",
|
|
"functions are bound to the context");
|
|
});
|
|
|
|
it("functions with context argument", function() {
|
|
shouldCompileTo("{{awesome frank}}",
|
|
{awesome: function(context) { return context; },
|
|
frank: "Frank"},
|
|
"Frank", "functions are called with context arguments");
|
|
});
|
|
it("pathed functions with context argument", function() {
|
|
shouldCompileTo("{{bar.awesome frank}}",
|
|
{bar: {awesome: function(context) { return context; }},
|
|
frank: "Frank"},
|
|
"Frank", "functions are called with context arguments");
|
|
});
|
|
it("depthed functions with context argument", function() {
|
|
shouldCompileTo("{{#with frank}}{{../awesome .}}{{/with}}",
|
|
{awesome: function(context) { return context; },
|
|
frank: "Frank"},
|
|
"Frank", "functions are called with context arguments");
|
|
});
|
|
|
|
it("block functions with context argument", function() {
|
|
shouldCompileTo("{{#awesome 1}}inner {{.}}{{/awesome}}",
|
|
{awesome: function(context, options) { return options.fn(context); }},
|
|
"inner 1", "block functions are called with context and options");
|
|
});
|
|
|
|
it("depthed block functions with context argument", function() {
|
|
shouldCompileTo("{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}",
|
|
{value: true, awesome: function(context, options) { return options.fn(context); }},
|
|
"inner 1", "block functions are called with context and options");
|
|
});
|
|
|
|
it("block functions without context argument", function() {
|
|
shouldCompileTo("{{#awesome}}inner{{/awesome}}",
|
|
{awesome: function(options) { return options.fn(this); }},
|
|
"inner", "block functions are called with options");
|
|
});
|
|
it("pathed block functions without context argument", function() {
|
|
shouldCompileTo("{{#foo.awesome}}inner{{/foo.awesome}}",
|
|
{foo: {awesome: function(options) { return this; }}},
|
|
"inner", "block functions are called with options");
|
|
});
|
|
it("depthed block functions without context argument", function() {
|
|
shouldCompileTo("{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}",
|
|
{value: true, awesome: function(options) { return this; }},
|
|
"inner", "block functions are called with options");
|
|
});
|
|
|
|
|
|
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 (-)");
|
|
});
|
|
|
|
it("nested paths", function() {
|
|
shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: "beautiful"}},
|
|
"Goodbye beautiful world!", "Nested paths access nested objects");
|
|
});
|
|
|
|
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");
|
|
});
|
|
|
|
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");
|
|
});
|
|
|
|
it('literal references', function() {
|
|
shouldCompileTo("Goodbye {{[foo bar]}} world!", {"foo bar": "beautiful"},
|
|
"Goodbye beautiful world!", "Literal paths can be used");
|
|
});
|
|
|
|
it("that current context path ({{.}}) doesn't hit helpers", function() {
|
|
shouldCompileTo("test: {{.}}", [null, {helper: "awesome"}], "test: ");
|
|
});
|
|
|
|
it("complex but empty paths", function() {
|
|
shouldCompileTo("{{person/name}}", {person: {name: null}}, "");
|
|
shouldCompileTo("{{person/name}}", {person: {}}, "");
|
|
});
|
|
|
|
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");
|
|
|
|
string = "{{#hellos}}{{this/text}}{{/hellos}}";
|
|
hash = {hellos: [{text: "hello"}, {text: "Hello"}, {text: "HELLO"}]};
|
|
shouldCompileTo(string, hash, "helloHelloHELLO", "This keyword evaluates in more complex paths");
|
|
});
|
|
|
|
it("this keyword nested inside path", function() {
|
|
var string = "{{#hellos}}{{text/this/foo}}{{/hellos}}";
|
|
shouldThrow(function() {
|
|
CompilerContext.compile(string);
|
|
}, Error);
|
|
});
|
|
|
|
it("this keyword in helpers", function() {
|
|
var helpers = {foo: function(value) {
|
|
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");
|
|
});
|
|
|
|
it("this keyword nested inside helpers param", function() {
|
|
var string = "{{#hellos}}{{foo text/this/foo}}{{/hellos}}";
|
|
shouldThrow(function() {
|
|
CompilerContext.compile(string);
|
|
}, Error);
|
|
});
|
|
});
|