base-test-suite
Version:
Test suite for base projects.
1,126 lines (959 loc) • 37.4 kB
JavaScript
var path = require('path');
var assert = require('assert');
var consolidate = require('consolidate');
var handlebars = require('engine-handlebars');
var matter = require('parser-front-matter');
var swig = consolidate.swig;
require('swig');
module.exports = function(App, options, runner) {
var fixtures = path.resolve.bind(path, __dirname, 'fixtures');
var app;
describe('helpers', function() {
describe('prototype methods', function() {
beforeEach(function() {
app = new App();
});
it('should expose `helper`', function() {
assert.equal(typeof app.helper, 'function');
});
it('should expose `asyncHelper`', function() {
assert.equal(typeof app.asyncHelper, 'function');
});
});
describe('helpers', function() {
beforeEach(function() {
app = new App();
});
it('should add a sync helper to the `sync` object:', function() {
app.helper('one', function() {});
assert.equal(typeof app._.helpers.sync.one, 'function');
});
it('should load a glob of sync helper functions:', function() {
app.helpers(fixtures('helpers/[a-c].js'));
assert.equal(typeof app._.helpers.sync.c, 'function');
assert.equal(typeof app._.helpers.sync.b, 'function');
assert.equal(typeof app._.helpers.sync.a, 'function');
});
it('should fail gracefully on bad globs:', function(cb) {
try {
app.helpers(fixtures('helpers/*.foo'));
cb();
} catch (err) {
cb(new Error('should not throw an error.'));
}
});
it('should add a glob of sync helper objects:', function() {
app.helpers(fixtures('helpers/!([a-c]).js'));
assert.equal(typeof app._.helpers.sync.one, 'function');
assert.equal(typeof app._.helpers.sync.two, 'function');
assert.equal(typeof app._.helpers.sync.three, 'function');
});
it('should add a glob with mixed helper objects and functions:', function() {
app.helpers(fixtures('helpers/*.js'));
assert.equal(typeof app._.helpers.sync.a, 'function');
assert.equal(typeof app._.helpers.sync.b, 'function');
assert.equal(typeof app._.helpers.sync.c, 'function');
assert.equal(typeof app._.helpers.sync.one, 'function');
assert.equal(typeof app._.helpers.sync.two, 'function');
assert.equal(typeof app._.helpers.sync.three, 'function');
});
it('should add an object of sync helpers to the `sync` object:', function() {
app.helpers({
x: function() {},
y: function() {},
z: function() {}
});
assert.equal(typeof app._.helpers.sync.x, 'function');
assert.equal(typeof app._.helpers.sync.y, 'function');
assert.equal(typeof app._.helpers.sync.z, 'function');
});
it('should add a helper "group":', function() {
app.helperGroup('foo', {
x: function() {},
y: function() {},
z: function() {}
});
assert.equal(typeof app._.helpers.sync.foo.x, 'function');
assert.equal(typeof app._.helpers.sync.foo.y, 'function');
assert.equal(typeof app._.helpers.sync.foo.z, 'function');
});
it('should merge helpers onto a helper "group":', function() {
app.helperGroup('foo', {
x: function() {},
y: function() {},
z: function() {}
});
assert.equal(typeof app._.helpers.sync.foo.x, 'function');
assert.equal(typeof app._.helpers.sync.foo.y, 'function');
assert.equal(typeof app._.helpers.sync.foo.z, 'function');
app.helperGroup('foo', {
a: function() {},
b: function() {},
c: function() {}
});
assert.equal(typeof app._.helpers.sync.foo.a, 'function');
assert.equal(typeof app._.helpers.sync.foo.b, 'function');
assert.equal(typeof app._.helpers.sync.foo.c, 'function');
assert.equal(typeof app._.helpers.sync.foo.x, 'function');
assert.equal(typeof app._.helpers.sync.foo.y, 'function');
assert.equal(typeof app._.helpers.sync.foo.z, 'function');
});
});
describe('async helpers', function() {
beforeEach(function() {
app = new App();
});
it('should add an async helper to the `async` object:', function() {
app.asyncHelper('two', function() {});
assert.equal(typeof app._.helpers.async.two, 'function');
});
it('should load a glob of async helper functions:', function() {
app.asyncHelpers(fixtures('helpers/[a-c].js'));
assert.equal(typeof app._.helpers.async.a, 'function');
assert.equal(typeof app._.helpers.async.b, 'function');
assert.equal(typeof app._.helpers.async.c, 'function');
});
it('should add a glob of async helper objects:', function() {
app.asyncHelpers(fixtures('helpers/!([a-c]).js'));
assert.equal(typeof app._.helpers.async.one, 'function');
assert.equal(typeof app._.helpers.async.two, 'function');
assert.equal(typeof app._.helpers.async.three, 'function');
});
it('should fail gracefully on bad globs:', function(cb) {
try {
app.asyncHelpers(fixtures('helpers/*.foo'));
cb();
} catch (err) {
cb(new Error('should not throw an error.'));
}
});
it('should add a glob with mixed helper objects and functions:', function() {
app.asyncHelpers(fixtures('helpers/*.js'));
assert.equal(typeof app._.helpers.async.a, 'function');
assert.equal(typeof app._.helpers.async.b, 'function');
assert.equal(typeof app._.helpers.async.c, 'function');
assert.equal(typeof app._.helpers.async.one, 'function');
assert.equal(typeof app._.helpers.async.two, 'function');
assert.equal(typeof app._.helpers.async.three, 'function');
});
it('should add an object of async helpers to the `async` object:', function() {
app.asyncHelpers({
x: function() {},
y: function() {},
z: function() {}
});
assert.equal(typeof app._.helpers.async.x, 'function');
assert.equal(typeof app._.helpers.async.y, 'function');
assert.equal(typeof app._.helpers.async.z, 'function');
});
it('should add an async helper "group":', function() {
app.helperGroup('foo', {
x: function() {},
y: function() {},
z: function() {}
}, true);
assert.equal(typeof app._.helpers.async.foo.x, 'function');
assert.equal(typeof app._.helpers.async.foo.y, 'function');
assert.equal(typeof app._.helpers.async.foo.z, 'function');
});
it('should merge helpers onto an async helper "group":', function() {
app.helperGroup('foo', {
x: function() {},
y: function() {},
z: function() {}
}, true);
assert.equal(typeof app._.helpers.async.foo.x, 'function');
assert.equal(typeof app._.helpers.async.foo.y, 'function');
assert.equal(typeof app._.helpers.async.foo.z, 'function');
app.helperGroup('foo', {
a: function() {},
b: function() {},
c: function() {}
}, true);
assert.equal(typeof app._.helpers.async.foo.a, 'function');
assert.equal(typeof app._.helpers.async.foo.b, 'function');
assert.equal(typeof app._.helpers.async.foo.c, 'function');
assert.equal(typeof app._.helpers.async.foo.x, 'function');
assert.equal(typeof app._.helpers.async.foo.y, 'function');
assert.equal(typeof app._.helpers.async.foo.z, 'function');
});
});
});
describe('sync helpers', function() {
beforeEach(function() {
app = new App();
app.engine('tmpl', require('engine-base'));
app.create('page');
});
it('should register a helper:', function() {
app.helper('a', function() {});
app.helper('b', function() {});
assert(app._.helpers.sync.hasOwnProperty('a'));
assert(app._.helpers.sync.hasOwnProperty('b'));
});
it('should use a helper:', function(cb) {
app.pages('a.tmpl', {path: 'a.tmpl', content: '<%= upper(a) %>', locals: {a: 'bbb'}});
app.helper('upper', function(str) {
return str.toUpperCase();
});
var page = app.pages.getView('a.tmpl');
app.render(page, function(err, view) {
if (err) return cb(err);
assert.equal(typeof view.contents.toString(), 'string');
assert.equal(view.contents.toString(), 'BBB');
cb();
});
});
it('should use a namespaced helper:', function(cb) {
app.pages('a.tmpl', {
path: 'a.tmpl',
content: '<%= foo.upper(a) %>',
locals: {
a: 'bbb'
}
});
app.helperGroup('foo', {
upper: function(str) {
return str.toUpperCase();
}
});
var page = app.pages.getView('a.tmpl');
app.render(page, function(err, view) {
if (err) return cb(err);
assert.equal(typeof view.contents.toString(), 'string');
assert.equal(view.contents.toString(), 'BBB');
cb();
});
});
});
describe('async helpers', function() {
beforeEach(function() {
app = new App();
app.engine('tmpl', require('engine-base'));
app.create('partials', {viewType: 'partial'});
app.create('page');
});
it('should register an async helper:', function() {
app.asyncHelper('a', function() {});
app.asyncHelper('b', function() {});
assert(app._.helpers.async.hasOwnProperty('a'));
assert(app._.helpers.async.hasOwnProperty('b'));
});
it('should use an async helper:', function(cb) {
app.pages('a.tmpl', {path: 'a.tmpl', content: '<%= lower(a) %>', locals: {a: 'BBB'}});
app.asyncHelper('lower', function(str, next) {
if (typeof next !== 'function') return str;
next(null, str.toLowerCase());
});
var page = app.pages.getView('a.tmpl');
app.render(page, function(err, view) {
if (err) return cb(err);
assert.equal(typeof view.content, 'string');
assert.equal(view.content, 'bbb');
cb();
});
});
it('should use load a file from the file system in a helper', function(cb) {
app.pages('a.tmpl', {path: 'a.tmpl', content: '<%= getPartial("posts/a.txt") %>', locals: {a: 'BBB'}});
app.asyncHelper('getPartial', function(name, next) {
var fp = path.resolve(__dirname, 'fixtures', name);
var view = this.app.partials.getView(fp);
next(null, view.content);
});
var page = app.pages.getView('a.tmpl');
app.render(page, function(err, view) {
if (err) return cb(err);
assert.equal(typeof view.content, 'string');
assert(/title/.test(view.content));
cb();
});
});
});
describe('built-in helpers:', function() {
describe('automatically generated helpers for default view types:', function() {
beforeEach(function() {
app = new App({rethrow: false});
app.engine('md', require('engine-base'));
app.engine('tmpl', require('engine-base'));
app.create('partials', { viewType: 'partial' });
app.create('pages');
// parse front matter
app.onLoad(/./, function(view, next) {
matter.parse(view, next);
});
});
it('should expose front matter to the `partial` helper.', function(cb) {
app.partial('a.md', {content: '---\nname: "AAA"\n---\n<%= name %>', locals: {name: 'BBB'}});
app.page('b.md', {path: 'b.md', content: 'foo <%= partial("a.md") %> bar'});
app.render('b.md', function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo AAA bar');
cb();
});
});
it('should emit `helper` when a built-in helper is called', function(cb) {
app.partial('a.md', {content: '---\nname: "AAA"\n---\n<%= name %>', locals: {name: 'BBB'}});
app.page('b.md', {path: 'b.md', content: 'foo <%= partial("a.md") %> bar'});
var count = 0;
app.once('helper', function(msg) {
assert(msg);
assert.equal(msg, 'partial helper > rendering "a.md"');
count++;
});
app.render('b.md', function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
cb();
});
});
it('should use helper locals.', function(cb) {
app.partial('abc.md', {content: '<%= name %>', locals: {name: 'BBB'}});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md", { name: "CCC" }) %> bar'});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo CCC bar');
cb();
});
});
it('should use front matter data.', function(cb) {
app.partial('abc.md', {content: '---\nname: "AAA"\n---\n<%= name %>'});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md") %> bar'});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo AAA bar');
cb();
});
});
it('should prefer helper locals over front-matter', function(cb) {
app.partial('abc.md', {content: '---\nname: "AAA"\n---\n<%= name %>', locals: {name: 'BBB'}});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md", { name: "CCC" }) %> bar'});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo CCC bar');
cb();
});
});
it('should use partial locals:', function(cb) {
app.partial('abc.md', {content: '<%= name %>', locals: {name: 'EEE'}});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md") %> bar'})
.render({name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo EEE bar');
cb();
});
});
it('should use locals from the `view.render` method:', function(cb) {
app.partial('abc.md', {content: '<%= name %>', locals: {name: 'EEE'}});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md") %> bar'})
.render({name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo EEE bar');
cb();
});
});
it('should use locals from the `app.render` method:', function(cb) {
app.partial('abc.md', {content: '<%= name %>'});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md") %> bar'});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo DDD bar');
cb();
});
});
it('should use a `helperContext` function from app.options', function(cb) {
app.option('helperContext', function(view, locals) {
return { name: 'blah' };
});
app.partial('abc.md', {content: '<%= name %>'});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md") %> bar'});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo blah bar');
cb();
});
});
it('should return an empty string when the partial is missing.', function(cb) {
app.partial('abc.md', {content: '---\nname: "AAA"\n---\n<%= name %>', locals: {name: 'BBB'}});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("def.md", { name: "CCC" }) %> bar'});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
assert(err);
assert.equal(err.message, 'helper "partial" cannot find "def.md"');
cb();
});
});
it('should return a List when no parameters are passed', function(cb) {
app.partial('abc.md', {content: '---\nname: "AAA"\n---\n<%= name %>', locals: {name: 'BBB'}});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= list(partials()) %> <%= partial("abc") %> bar'});
app.helper('list', function(list) {
return list.keys.join(' ');
});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo abc.md AAA bar');
cb();
});
});
});
describe('helper context:', function() {
beforeEach(function() {
app = new App({rethrow: false});
app.engine(['tmpl', 'md'], require('engine-base'));
app.create('partial', { viewType: 'partial' });
app.create('page');
// parse front matter
app.onLoad(/./, function(view, next) {
matter.parse(view, next);
});
});
it('should expose a "this" object', function(cb) {
app.partial('abc.md', {content: '<%= name %>', name: 'BBB'});
app.page('xyz.md', {path: 'xyz.md', content: 'a <%= foo() %> b'});
var count = 0;
app.option('helper.foo', {some: 'opt'});
app.helper('foo', function() {
assert(this);
count++;
return 'foo';
});
app.render('xyz.md', function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a foo b');
cb();
});
});
it('should expose a "this.helper" object', function(cb) {
app.partial('abc.md', {content: '<%= name %>', name: 'BBB'});
app.page('xyz.md', {path: 'xyz.md', content: 'a <%= foo() %> b'});
var count = 0;
app.option('helper.foo', {some: 'opt'});
app.helper('foo', function() {
assert(this.helper);
assert.equal(typeof this.helper, 'object');
count++;
return 'foo';
});
app.render('xyz.md', function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a foo b');
cb();
});
});
it('should expose a "this.options" object', function(cb) {
app.partial('abc.md', {content: '<%= name %>', name: 'BBB'});
app.page('xyz.md', {path: 'xyz.md', content: 'a <%= foo() %> b'});
var count = 0;
app.option('helper.foo', {some: 'opt'});
app.helper('foo', function() {
assert(this.options);
assert.equal(typeof this.options, 'object');
count++;
return 'foo';
});
app.render('xyz.md', function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a foo b');
cb();
});
});
it('should expose a "this.context" object', function(cb) {
app.partial('abc.md', {content: '<%= name %>', name: 'BBB'});
app.page('xyz.md', {path: 'xyz.md', content: 'a <%= foo() %> b'});
var count = 0;
app.option('helper.foo', {some: 'opt'});
app.helper('foo', function() {
assert(this.context);
assert.equal(typeof this.context, 'object');
count++;
return 'foo';
});
app.render('xyz.md', function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a foo b');
cb();
});
});
it('should prefer helper locals over view locals.', function(cb) {
app.partial('abc.md', {content: '<%= name %>', name: 'BBB'});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md", { name: "CCC" }) %> bar'});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo CCC bar');
cb();
});
});
it('should give preference to view locals over render locals.', function(cb) {
app.partial('abc.md', {content: '<%= name %>', locals: {name: 'BBB'}});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md") %> bar'});
var page = app.pages.getView('xyz.md');
app.render(page, {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo BBB bar');
cb();
});
});
it('should use render locals when other locals are not defined.', function(cb) {
app.partial('abc.md', {content: '<%= name %>'});
app.page('xyz.md', {path: 'xyz.md', content: 'foo <%= partial("abc.md") %> bar'});
app.render('xyz.md', {name: 'DDD'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo DDD bar');
cb();
});
});
});
describe('user-defined engines:', function() {
beforeEach(function() {
app = new App({rethrow: false});
app.create('partial', { viewType: 'partial' });
app.create('page');
// parse front matter
app.onLoad(/./, function(view, next) {
matter.parse(view, next);
});
});
it('should use the `partial` helper with handlebars.', function(cb) {
app.engine(['tmpl', 'md'], require('engine-base'));
app.engine('hbs', handlebars);
app.partial('title.hbs', {content: '<title>{{name}}</title>', locals: {name: 'BBB'}});
app.page('a.hbs', {path: 'a.hbs', content: 'foo {{{partial "title.hbs" this}}} bar'});
app.render('a.hbs', {name: 'Halle Nicole'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo <title>Halle Nicole</title> bar');
cb();
});
});
it('should use the `partial` helper with any engine.', function(cb) {
app.engine('hbs', handlebars);
app.engine('md', handlebars);
app.engine('swig', swig);
app.engine('tmpl', require('engine-base'));
/**
* Partial
*/
app.partial('a.hbs', {
content: '---\nname: "AAA"\n---\n<title>{{name}}</title>',
locals: {
name: 'BBB'
}
});
/**
* Pages
*/
app.page('a.hbs', {
path: 'a.hbs',
content: '<title>{{author}}</title>',
locals: {
author: 'Halle Nicole'
}
});
app.page('b.tmpl', {
path: 'b.tmpl',
content: '<title><%= author %></title>',
locals: {
author: 'Halle Nicole'
}
});
app.page('d.swig', {
path: 'd.swig',
content: '<title>{{author}}</title>',
locals: {
author: 'Halle Nicole'
}
});
app.page('e.swig', {
path: 'e.swig',
content: '<title>{{author}}</title>',
locals: {
author: 'Halle Nicole'
}
});
app.page('f.hbs', {
content: '<title>{{author}}</title>',
locals: {
author: 'Halle Nicole'
}
});
app.page('g.md', {
content: '---\nauthor: Brian Woodward\n---\n<title>{{author}}</title>',
locals: {
author: 'Halle Nicole'
}
});
app.page('with-partial.hbs', {
path: 'with-partial.hbs',
content: '{{{partial "a.hbs" custom.locals}}}'
});
var locals = {custom: {locals: {name: 'Halle Nicole' }}};
app.render('a.hbs', locals, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, '<title>Halle Nicole</title>');
app.emit('one');
});
app.on('one', function() {
app.render('with-partial.hbs', locals, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, '<title>Halle Nicole</title>');
app.emit('two');
});
});
var page = app.pages.getView('g.md');
locals.author = page.data.author || locals.author;
app.on('two', function() {
page.render(locals, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, '<title>Brian Woodward</title>');
cb(null, res.content);
});
});
});
});
});
describe('helper debug', function() {
beforeEach(function() {
app = new App();
app.create('pages');
app.engine('hbs', require('engine-handlebars'));
app.engine('md', require('engine-base'));
});
it('should expose a `debug` method on the context', function(cb) {
var count = 0;
app.helper('foo', function(str) {
assert.equal(typeof this.debug, 'function');
this.debug('rendering "%s"', str);
count++;
return str;
});
app.page('doc.md', {content: 'a <%= foo("some string") %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a some string b');
cb();
});
});
});
describe('helpers integration', function() {
beforeEach(function() {
app = new App();
app.create('pages');
app.engine('hbs', require('engine-handlebars'));
app.engine('md', require('engine-base'));
});
describe('.helpers()', function() {
it('should add helpers and use them in templates.', function(cb) {
app.helpers({
upper: function(str) {
return str.toUpperCase();
}
});
app.page('doc.md', {content: 'a <%= upper(name) %> b'})
.render({name: 'Halle'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'a HALLE b');
cb();
});
});
});
describe('helper options:', function() {
it('should expose global options to helpers:', function(cb) {
app.helper('cwd', function(fp) {
return path.join(this.options.cwd, fp);
});
app.option('cwd', 'foo/bar');
app.page('doc.md', {content: 'a <%= cwd("baz") %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'a foo/bar/baz b');
cb();
});
});
it('should expose helper-specific options to helpers:', function(cb) {
app.helper('cwd', function(fp) {
return path.join(this.options.cwd, fp);
});
app.option('helper.cwd', 'foo/bar');
app.page('doc.md', {content: 'a <%= cwd("baz") %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'a foo/bar/baz b');
cb();
});
});
it('should prefer helper options over global options:', function(cb) {
app.helper('cwd', function(fp) {
return path.join(this.options.cwd, fp);
});
app.option('cwd', 'one/two');
app.option('helper.cwd', 'foo/bar');
app.page('doc.md', {content: 'a <%= cwd("baz") %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'a foo/bar/baz b');
cb();
});
});
it('should expose a `merge` method on context options', function(cb) {
var count = 0;
app.helper('foo', function(str) {
assert.equal(typeof this.options.merge, 'function');
count++;
return str;
});
app.page('doc.md', {content: 'a <%= foo("foo") %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a foo b');
cb();
});
});
it('should merge the given object onto context options', function(cb) {
var count = 0;
app.helper('foo', function(options) {
this.options.merge(options);
count++;
return this.options.one;
});
app.page('doc.md', {content: 'a <%= foo({one: "two"}) %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a two b');
cb();
});
});
it('should merge a list of objects onto context options', function(cb) {
var count = 0;
app.helper('foo', function(locals, options) {
this.options.merge(locals, options);
count++;
return this.options.abc + this.options.one;
});
app.page('doc.md', {content: 'a <%= foo({abc: "def"}, {one: "two"}) %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a deftwo b');
cb();
});
});
it('should merge the handlebars "hash" object onto context options', function(cb) {
var count = 0;
app.helper('foo', function(options) {
this.options.merge(options);
count++;
return this.options.abc;
});
app.page('doc.hbs', {content: 'a {{foo abc="xyz"}} b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a xyz b');
cb();
});
});
it('should expose a `get` method on context options', function(cb) {
var count = 0;
app.helper('foo', function(str) {
assert.equal(typeof this.options.get, 'function');
count++;
return str;
});
app.page('doc.md', {content: 'a <%= foo("foo") %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a foo b');
cb();
});
});
it('should expose a `set` method on context options', function(cb) {
var count = 0;
app.helper('foo', function(str) {
assert.equal(typeof this.options.set, 'function');
count++;
return str;
});
app.page('doc.md', {content: 'a <%= foo("foo") %> b'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(count, 1);
assert.equal(res.content, 'a foo b');
cb();
});
});
});
describe('options.helpers', function() {
it('should register helpers passed on the options:', function(cb) {
app.option({
helpers: {
upper: function(str) {
return str.toUpperCase();
},
foo: function(str) {
return 'foo' + str;
}
}
});
app.page('doc.md', {content: 'a <%= upper(name) %> <%= foo("bar") %> b'})
.render({name: 'Halle'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'a HALLE foobar b');
cb();
});
});
});
describe('options.helpers', function() {
it('should add helpers and use them in templates.', function(cb) {
app.options.helpers = {
upper: function(str) {
return str.toUpperCase();
},
foo: function(str) {
return 'foo' + str;
}
};
app.page('doc.md', {content: 'a <%= upper(name) %> b'})
.render({name: 'Halle'}, function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'a HALLE b');
cb();
});
});
});
});
describe('collection helpers', function() {
beforeEach(function() {
app = new App();
app.create('posts');
app.create('pages', {engine: 'hbs'});
app.create('partials', {viewType: 'partial', engine: 'hbs'});
app.create('snippet', {viewType: 'partial'});
app.engine('hbs', require('engine-handlebars'));
app.helper('log', function(ctx) {
// console.log(ctx);
});
});
describe('plural', function() {
it('should get the given collection as a block helper', function(cb) {
app.post('a.hbs', {content: 'foo'});
app.post('b.hbs', {content: 'bar'});
app.post('c.hbs', {content: 'baz'});
app.partial('list.hbs', {
content: '{{#posts}}{{#each items}}{{content}}{{/each}}{{/posts}}'
});
app.page('index.hbs', {
content: '{{> list.hbs }}'
})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foobarbaz');
cb();
});
});
it('should get the given collection as a helper expression', function(cb) {
app.post('a.hbs', {content: 'foo'});
app.post('b.hbs', {content: 'bar'});
app.post('c.hbs', {content: 'baz'});
app.helper('list', function(list) {
return list.items.map(function(item) {
return '- ' + item.content;
}).join('\n');
});
app.partial('list.hbs', {content: '{{list (posts)}}'});
app.page('index.hbs', {content: '{{> list.hbs }}'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(res.content, '- foo\n- bar\n- baz');
cb();
});
});
});
describe('single', function() {
it('should get a view from an unspecified collection', function(cb) {
app.post('a.hbs', {content: 'post-a'});
app.post('b.hbs', {content: 'post-b'});
app.page('one', {content: '{{view "a.hbs"}}'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'post-a');
cb();
});
});
it('should return an empty string if not found', function(cb) {
app.page('one', {content: '{{view "foo.hbs"}}'})
.render(function(err, view) {
if (err) return cb(err);
assert.equal(view.content, '');
cb();
});
});
it('should handle engine errors', function(cb) {
app.post('foo.hbs', {content: '{{one "two"}}'});
app.page('one', {content: '{{post "foo.hbs"}}'})
.render(function(err) {
assert(err);
assert.equal(typeof err, 'object');
assert.equal(typeof err.message, 'string');
assert(/Missing helper: "one"/.test(err.message));
cb();
});
});
it('should handle engine errors2', function(cb) {
app.engine('tmpl', require('engine-base'));
app.create('foo', {viewType: 'partial', engine: 'tmpl'});
app.create('bar', {engine: 'tmpl'});
app.foo('a.tmpl', {path: 'a.tmpl', content: '<%= blah.bar %>'});
app.bar('b.tmpl', {content: '<%= foo("a.tmpl") %>'})
.render(function(err) {
assert(err);
assert.equal(typeof err, 'object');
assert(/blah is not defined/.test(err.message));
cb();
});
});
it('should work with non-handlebars engine', function(cb) {
app.engine('tmpl', require('engine-base'));
app.create('foo', {engine: 'tmpl'});
app.create('bar', {engine: 'tmpl'});
app.foo('a.tmpl', {content: 'foo-a'});
app.bar('b.tmpl', {content: 'bar-b'});
app.bar('one', {content: '<%= view("a.tmpl", "foos", { render: true }) %>'})
.render(function(err, res) {
if (err) return cb(err);
assert.equal(res.content, 'foo-a');
app.bar('two', {content: '<%= view("b.tmpl", "bars", { render: true }) %>'})
.render(function(err, bar) {
if (err) return cb(err);
assert.equal(bar.content, 'bar-b');
cb();
});
});
});
it('should render a specific view from the given collection', function(cb) {
app.post('a.hbs', {content: 'post-a'});
app.post('b.hbs', {content: 'post-b'});
app.post('c.hbs', {content: 'post-c'});
app.page('a.hbs', {content: 'page-a'});
app.page('b.hbs', {content: 'page-b'});
app.page('c.hbs', {content: 'page-c'});
app.page('one', {content: '{{view "a.hbs" "posts" render=true}}'})
.render(function(err, post) {
if (err) return cb(err);
assert.equal(post.content, 'post-a');
app.page('two', {content: '{{view "b.hbs" "pages" render=true}}'})
.render(function(err, page) {
if (err) return cb(err);
assert.equal(page.content, 'page-b');
cb();
});
});
});
});
});
};
;