summaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/blocks.js178
-rw-r--r--spec/parser.js14
-rw-r--r--spec/partials.js39
-rw-r--r--spec/runtime.js6
-rw-r--r--spec/tokenizer.js9
-rw-r--r--spec/visitor.js2
6 files changed, 245 insertions, 3 deletions
diff --git a/spec/blocks.js b/spec/blocks.js
index 71c9045..2fbaee7 100644
--- a/spec/blocks.js
+++ b/spec/blocks.js
@@ -166,4 +166,182 @@ describe('blocks', function() {
shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel ');
});
});
+
+ describe('decorators', function() {
+ it('should apply mustache decorators', function() {
+ var helpers = {
+ helper: function(options) {
+ return options.fn.run;
+ }
+ };
+ var decorators = {
+ decorator: function(fn) {
+ fn.run = 'success';
+ return fn;
+ }
+ };
+ shouldCompileTo(
+ '{{#helper}}{{*decorator}}{{/helper}}',
+ {hash: {}, helpers: helpers, decorators: decorators},
+ 'success');
+ });
+ it('should apply allow undefined return', function() {
+ var helpers = {
+ helper: function(options) {
+ return options.fn() + options.fn.run;
+ }
+ };
+ var decorators = {
+ decorator: function(fn) {
+ fn.run = 'cess';
+ }
+ };
+ shouldCompileTo(
+ '{{#helper}}{{*decorator}}suc{{/helper}}',
+ {hash: {}, helpers: helpers, decorators: decorators},
+ 'success');
+ });
+
+ it('should apply block decorators', function() {
+ var helpers = {
+ helper: function(options) {
+ return options.fn.run;
+ }
+ };
+ var decorators = {
+ decorator: function(fn, props, container, options) {
+ fn.run = options.fn();
+ return fn;
+ }
+ };
+ shouldCompileTo(
+ '{{#helper}}{{#*decorator}}success{{/decorator}}{{/helper}}',
+ {hash: {}, helpers: helpers, decorators: decorators},
+ 'success');
+ });
+ it('should support nested decorators', function() {
+ var helpers = {
+ 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');
+ });
+
+ it('should apply multiple decorators', function() {
+ var helpers = {
+ helper: function(options) {
+ return options.fn.run;
+ }
+ };
+ var decorators = {
+ 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');
+ });
+
+ it('should access parent variables', function() {
+ var helpers = {
+ helper: function(options) {
+ return options.fn.run;
+ }
+ };
+ var decorators = {
+ 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');
+ });
+ it('should work with root program', function() {
+ var run;
+ var decorators = {
+ decorator: function(fn, props, container, options) {
+ equals(options.args[0], 'success');
+ run = true;
+ return fn;
+ }
+ };
+ shouldCompileTo(
+ '{{*decorator "success"}}',
+ {hash: {'foo': 'success'}, decorators: decorators},
+ '');
+ equals(run, true);
+ });
+ it('should fail when accessing variables from root', function() {
+ var run;
+ var decorators = {
+ decorator: function(fn, props, container, options) {
+ equals(options.args[0], undefined);
+ run = true;
+ return fn;
+ }
+ };
+ shouldCompileTo(
+ '{{*decorator foo}}',
+ {hash: {'foo': 'fail'}, decorators: decorators},
+ '');
+ equals(run, true);
+ });
+
+ describe('registration', function() {
+ it('unregisters', function() {
+ handlebarsEnv.decorators = {};
+
+ handlebarsEnv.registerDecorator('foo', function() {
+ return 'fail';
+ });
+
+ equals(!!handlebarsEnv.decorators.foo, true);
+ handlebarsEnv.unregisterDecorator('foo');
+ equals(handlebarsEnv.decorators.foo, undefined);
+ });
+
+ it('allows multiple globals', function() {
+ handlebarsEnv.decorators = {};
+
+ handlebarsEnv.registerDecorator({
+ foo: function() {},
+ bar: function() {}
+ });
+
+ equals(!!handlebarsEnv.decorators.foo, true);
+ equals(!!handlebarsEnv.decorators.bar, true);
+ handlebarsEnv.unregisterDecorator('foo');
+ handlebarsEnv.unregisterDecorator('bar');
+ equals(handlebarsEnv.decorators.foo, undefined);
+ equals(handlebarsEnv.decorators.bar, undefined);
+ });
+ it('fails with multiple and args', function() {
+ shouldThrow(function() {
+ handlebarsEnv.registerDecorator({
+ world: function() { return 'world!'; },
+ testHelper: function() { return 'found it!'; }
+ }, {});
+ }, Error, 'Arg not supported with multiple decorators');
+ });
+ });
+ });
});
diff --git a/spec/parser.js b/spec/parser.js
index 5b60f93..3b7e3e4 100644
--- a/spec/parser.js
+++ b/spec/parser.js
@@ -247,6 +247,20 @@ describe('parser', function() {
});
});
+ describe('directives', function() {
+ it('should parse block directives', function() {
+ equals(astFor('{{#* foo}}{{/foo}}'), 'DIRECTIVE BLOCK:\n PATH:foo []\n PROGRAM:\n');
+ });
+ it('should parse directives', function() {
+ equals(astFor('{{* foo}}'), '{{ DIRECTIVE PATH:foo [] }}\n');
+ });
+ it('should fail if directives have inverse', function() {
+ shouldThrow(function() {
+ astFor('{{#* foo}}{{^}}{{/foo}}');
+ }, Error, /Unexpected inverse/);
+ });
+ });
+
it('GH1024 - should track program location properly', function() {
var p = Handlebars.parse('\n'
+ ' {{#if foo}}\n'
diff --git a/spec/partials.js b/spec/partials.js
index 314cca2..f3283ba 100644
--- a/spec/partials.js
+++ b/spec/partials.js
@@ -257,6 +257,45 @@ describe('partials', function() {
});
});
+ describe('inline partials', function() {
+ it('should define inline partials for template', function() {
+ shouldCompileTo('{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}', {}, 'success');
+ });
+ it('should overwrite multiple partials in the same template', function() {
+ shouldCompileTo('{{#*inline "myPartial"}}fail{{/inline}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}', {}, 'success');
+ });
+ it('should define inline partials for block', function() {
+ shouldCompileTo('{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}', {}, 'success');
+ shouldThrow(function() {
+ shouldCompileTo('{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{/with}}{{> myPartial}}', {}, 'success');
+ }, Error, /myPartial could not/);
+ });
+ it('should override global partials', function() {
+ shouldCompileTo('{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}', {hash: {}, partials: {myPartial: function() { return 'fail'; }}}, 'success');
+ });
+ it('should override template partials', function() {
+ shouldCompileTo('{{#*inline "myPartial"}}fail{{/inline}}{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{> myPartial}}{{/with}}', {}, 'success');
+ });
+ it('should override partials down the entire stack', function() {
+ shouldCompileTo('{{#with .}}{{#*inline "myPartial"}}success{{/inline}}{{#with .}}{{#with .}}{{> myPartial}}{{/with}}{{/with}}{{/with}}', {}, 'success');
+ });
+
+ it('should define inline partials for partial call', function() {
+ shouldCompileToWithPartials(
+ '{{#*inline "myPartial"}}success{{/inline}}{{> dude}}',
+ [{}, {}, {dude: '{{> myPartial }}'}],
+ true,
+ 'success');
+ });
+ it('should define inline partials in partial block call', function() {
+ shouldCompileToWithPartials(
+ '{{#> dude}}{{#*inline "myPartial"}}success{{/inline}}{{/dude}}',
+ [{}, {}, {dude: '{{> myPartial }}'}],
+ true,
+ 'success');
+ });
+ });
+
it('should pass compiler flags', function() {
if (Handlebars.compile) {
var env = Handlebars.create();
diff --git a/spec/runtime.js b/spec/runtime.js
index 502a843..a4830ad 100644
--- a/spec/runtime.js
+++ b/spec/runtime.js
@@ -14,19 +14,19 @@ describe('runtime', function() {
it('should throw on version mismatch', function() {
shouldThrow(function() {
Handlebars.template({
- main: true,
+ main: {},
compiler: [Handlebars.COMPILER_REVISION + 1]
});
}, Error, /Template was precompiled with a newer version of Handlebars than the current runtime/);
shouldThrow(function() {
Handlebars.template({
- main: true,
+ main: {},
compiler: [Handlebars.COMPILER_REVISION - 1]
});
}, Error, /Template was precompiled with an older version of Handlebars than the current runtime/);
shouldThrow(function() {
Handlebars.template({
- main: true
+ main: {}
});
}, Error, /Template was precompiled with an older version of Handlebars than the current runtime/);
});
diff --git a/spec/tokenizer.js b/spec/tokenizer.js
index f170704..dc077ce 100644
--- a/spec/tokenizer.js
+++ b/spec/tokenizer.js
@@ -241,6 +241,15 @@ describe('Tokenizer', function() {
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'CLOSE', 'CONTENT', 'OPEN_ENDBLOCK', 'ID', 'CLOSE']);
});
+ it('tokenizes directives', function() {
+ shouldMatchTokens(
+ tokenize('{{#*foo}}content{{/foo}}'),
+ ['OPEN_BLOCK', 'ID', 'CLOSE', 'CONTENT', 'OPEN_ENDBLOCK', 'ID', 'CLOSE']);
+ shouldMatchTokens(
+ tokenize('{{*foo}}'),
+ ['OPEN', 'ID', 'CLOSE']);
+ });
+
it('tokenizes inverse sections as "INVERSE"', function() {
shouldMatchTokens(tokenize('{{^}}'), ['INVERSE']);
shouldMatchTokens(tokenize('{{else}}'), ['INVERSE']);
diff --git a/spec/visitor.js b/spec/visitor.js
index 3e2d523..d3fb795 100644
--- a/spec/visitor.js
+++ b/spec/visitor.js
@@ -9,6 +9,8 @@ describe('Visitor', function() {
var visitor = new Handlebars.Visitor();
visitor.accept(Handlebars.parse('{{foo}}{{#foo (bar 1 "1" true undefined null) foo=@data}}{{!comment}}{{> bar }} {{/foo}}'));
visitor.accept(Handlebars.parse('{{#> bar }} {{/bar}}'));
+ visitor.accept(Handlebars.parse('{{#* bar }} {{/bar}}'));
+ visitor.accept(Handlebars.parse('{{* bar }}'));
});
it('should traverse to stubs', function() {