2
1
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2023-12-13 21:00:40 +01:00

🔥 🎨 Cleanup & simplify theme helpers (#8223)

no issue

🔥 Remove adminHbs concept from tests
🔥 Get rid of unnecessary helper test utils
🔥 Remove helper missing code
- this hasn't been registered / used for ages 😱
- gscan no longer allows us to activate themes that have missing helpers, so this wouldn't be used anyway
TODO: consider whether we should make a way to override this?

🎨 Reduce coupling inside of /helpers
🎨 Use settingsCache in ghost_foot
 Labs util for enabling helpers
🎨 Move loadCoreHelpers to blog
- This needs a proper home, but at the very least it doesn't belong
in server/app.js!

🎨 Use settingsCache in ghost_head
This commit is contained in:
Hannah Wolfe 2017-03-23 19:00:58 +00:00 committed by Katharina Irrgang
parent 5b161a2856
commit 3cea203459
40 changed files with 229 additions and 478 deletions

View file

@ -52,11 +52,6 @@ module.exports = function setupParentApp() {
// This sets global res.locals which are needed everywhere
parentApp.use(ghostLocals);
// @TODO where should this live?!
// Load helpers
require('./helpers').loadCoreHelpers();
debug('Helpers done');
// Mount the apps on the parentApp
// API
// @TODO: finish refactoring the API app

View file

@ -1,32 +1,20 @@
// Dirty requires!
var hbs = require('express-hbs'),
logging = require('../../../../logging'),
i18n = require('../../../../i18n'),
labs = require('../../../../utils/labs'),
errorMessages = [
i18n.t('warnings.helpers.helperNotAvailable', {helperName: 'subscribe_form'}),
i18n.t('warnings.helpers.apiMustBeEnabled', {helperName: 'subscribe_form', flagName: 'subscribers'}),
i18n.t('warnings.helpers.seeLink', {url: 'http://support.ghost.org/subscribers-beta/'})
];
var labs = require('../../../../utils/labs');
module.exports = function registerHelpers(ghost) {
var err;
ghost.helpers.register('input_email', require('./input_email'));
ghost.helpers.register('subscribe_form', function labsEnabledHelper() {
if (labs.isSet('subscribers') === true) {
return require('./subscribe_form').apply(this, arguments);
}
var self = this,
args = arguments;
err = new Error();
err.message = i18n.t('warnings.helpers.helperNotAvailable', {helperName: 'subscribe_form'});
err.context = i18n.t('warnings.helpers.apiMustBeEnabled', {helperName: 'subscribe_form', flagName: 'subscribers'});
err.help = i18n.t('warnings.helpers.seeLink', {url: 'http://support.ghost.org/subscribers-beta/'});
logging.error(err);
return new hbs.handlebars.SafeString('<script>console.error("' + errorMessages.join(' ') + '");</script>');
return labs.enabledHelper({
flagKey: 'subscribers',
flagName: 'Subscribers',
helperName: 'subscribe_form',
helpUrl: 'http://support.ghost.org/subscribers-beta/'
}, function executeHelper() {
return require('./subscribe_form').apply(self, args);
});
});
};

View file

@ -53,6 +53,13 @@ module.exports = function setupBlogApp() {
// Serve blog images using the storage adapter
blogApp.use('/' + utils.url.STATIC_IMAGE_URL_PREFIX, storage.getStorage().serve());
// @TODO find this a better home
// We do this here, at the top level, because helpers require so much stuff.
// Moving this to being inside themes, where it probably should be requires the proxy to be refactored
// Else we end up with circular dependencies
require('../helpers').loadCoreHelpers();
debug('Helpers done');
// Theme middleware
// This should happen AFTER any shared assets are served, as it only changes things to do with templates
// At this point the active theme object is already updated, so we have the right path, so it can probably

View file

@ -1,24 +1,24 @@
// # Get Helper
// Usage: `{{#get "posts" limit="5"}}`, `{{#get "tags" limit="all"}}`
// Fetches data from the API
var _ = require('lodash'),
hbs = require('express-hbs'),
Promise = require('bluebird'),
errors = require('../errors'),
logging = require('../logging'),
api = require('../api'),
jsonpath = require('jsonpath'),
labs = require('../utils/labs'),
i18n = require('../i18n'),
var _ = require('lodash'),
hbs = require('express-hbs'),
Promise = require('bluebird'),
jsonpath = require('jsonpath'),
logging = require('../logging'),
i18n = require('../i18n'),
api = require('../api'),
labs = require('../utils/labs'),
resources,
pathAliases,
get;
// Endpoints that the helper is able to access
resources = ['posts', 'tags', 'users'];
resources = ['posts', 'tags', 'users'];
// Short forms of paths which we should understand
pathAliases = {
pathAliases = {
'post.tags': 'post.tags[*].slug',
'post.author': 'post.author.slug'
};
@ -139,23 +139,17 @@ get = function get(resource, options) {
});
};
module.exports = function getWithLabs(resource, options) {
var self = this, err;
module.exports = function getLabsWrapper() {
var self = this,
args = arguments;
if (labs.isSet('publicAPI') === true) {
// get helper is active
return get.call(self, resource, options);
} else {
err = new errors.GhostError({
message: i18n.t('warnings.helpers.get.helperNotAvailable'),
context: i18n.t('warnings.helpers.get.apiMustBeEnabled'),
help: i18n.t('warnings.helpers.get.seeLink', {url: 'http://support.ghost.org/public-api-beta'})
});
logging.error(err);
return Promise.resolve(function noGetHelper() {
return '<script>console.error(' + JSON.stringify(err) + ');</script>';
});
}
return labs.enabledHelper({
flag: 'publicAPI',
flagName: 'Public API',
helperName: 'get',
helpUrl: 'http://support.ghost.org/public-api-beta/',
async: true
}, function executeHelper() {
return get.apply(self, args);
});
};

View file

@ -5,24 +5,26 @@
//
// We use the name ghost_foot to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var hbs = require('express-hbs'),
_ = require('lodash'),
filters = require('../filters'),
api = require('../api'),
var hbs = require('express-hbs'),
SafeString = hbs.handlebars.SafeString,
_ = require('lodash'),
filters = require('../filters'),
settingsCache = require('../settings/cache'),
ghost_foot;
ghost_foot = function (options) {
/*jshint unused:false*/
var foot = [];
ghost_foot = function ghost_foot() {
var foot = [],
codeInjection = settingsCache.get('ghost_foot');
return api.settings.read({key: 'ghost_foot'}).then(function (response) {
foot.push(response.settings[0].value);
return filters.doFilter('ghost_foot', foot);
}).then(function (foot) {
var footString = _.reduce(foot, function (memo, item) { return memo + ' ' + item; }, '');
return new hbs.handlebars.SafeString(footString.trim());
});
if (!_.isEmpty(codeInjection)) {
foot.push(codeInjection);
}
return filters
.doFilter('ghost_foot', foot)
.then(function (foot) {
return new SafeString(foot.join(' ').trim());
});
};
module.exports = ghost_foot;

View file

@ -85,6 +85,7 @@ function ghost_head(options) {
var metaData,
client,
head = [],
codeInjection = settingsCache.get('ghost_head'),
context = this.context ? this.context : null,
useStructuredData = !config.isPrivacyDisabled('useStructuredData'),
safeVersion = this.safeVersion,
@ -153,11 +154,9 @@ function ghost_head(options) {
escapeExpression(metaData.blog.title) + '" href="' +
escapeExpression(metaData.rssUrl) + '" />');
return api.settings.read({key: 'ghost_head'});
}).then(function (response) {
// no code injection for amp context!!!
if (!_.includes(context, 'amp')) {
head.push(response.settings[0].value);
if (!_.includes(context, 'amp') && !_.isEmpty(codeInjection)) {
head.push(codeInjection);
}
return filters.doFilter('ghost_head', head);
}).then(function (head) {

View file

@ -1,13 +1,12 @@
var hbs = require('express-hbs'),
Promise = require('bluebird'),
errors = require('../errors'),
logging = require('../logging'),
utils = require('./utils'),
i18n = require('../i18n'),
config = require('../config'),
coreHelpers = {},
registerHelpers;
if (!utils.isProduction) {
// @TODO think about a config option for this e.g. theme.devmode?
if (config.get('env') !== 'production') {
hbs.handlebars.logger.level = 0;
}
@ -40,16 +39,6 @@ coreHelpers.title = require('./title');
coreHelpers.twitter_url = require('./twitter_url');
coreHelpers.url = require('./url');
coreHelpers.helperMissing = function (arg) {
if (arguments.length === 2) {
return undefined;
}
logging.error(new errors.GhostError({
message: i18n.t('warnings.helpers.index.missingHelper', {arg: arg})
}));
};
// Register an async handlebars helper for a given handlebars instance
function registerAsyncHelper(hbs, name, fn) {
hbs.registerAsyncHelper(name, function (context, options, cb) {

View file

@ -1,5 +1,4 @@
var _ = require('lodash'),
config = require('../config'),
utils;
utils = {
@ -7,7 +6,6 @@ utils = {
linkTemplate: _.template('<a href="<%= url %>"><%= text %></a>'),
scriptTemplate: _.template('<script src="<%= source %>?v=<%= version %>"></script>'),
inputTemplate: _.template('<input class="<%= className %>" type="<%= type %>" name="<%= name %>" <%= extras %> />'),
isProduction: config.get('env') === 'production',
// @TODO this can probably be made more generic and used in more places
findKey: function findKey(key, object, data) {
if (object && _.has(object, key) && !_.isEmpty(object[key])) {

View file

@ -483,17 +483,14 @@
},
"helpers": {
"helperNotAvailable": "The \\{\\{{helperName}\\}\\} helper is not available.",
"apiMustBeEnabled": "The {flagName} labs flag must be enabled if you wish to use the \\{\\{{helperName}\\}\\} helper.",
"flagMustBeEnabled": "The {flagName} labs flag must be enabled if you wish to use the \\{\\{{helperName}\\}\\} helper.",
"seeLink": "See {url}",
"foreach": {
"iteratorNeeded": "Need to pass an iterator to #foreach"
},
"get": {
"mustBeCalledAsBlock": "Get helper must be called as a block",
"invalidResource": "Invalid resource given to get helper",
"helperNotAvailable": "The \\{\\{get\\}\\} helper is not available.",
"apiMustBeEnabled": "Public API access must be enabled if you wish to use the \\{\\{get\\}\\} helper.",
"seeLink": "See {url}"
"invalidResource": "Invalid resource given to get helper"
},
"has": {
"invalidAttribute": "Invalid or no attribute given to has helper"

View file

@ -1,9 +1,46 @@
var settingsCache = require('../settings/cache'),
flagIsSet;
_ = require('lodash'),
Promise = require('bluebird'),
hbs = require('express-hbs'),
errors = require('../errors'),
logging = require('../logging'),
i18n = require('../i18n'),
labs = module.exports = {};
flagIsSet = function flagIsSet(flag) {
labs.isSet = function isSet(flag) {
var labsConfig = settingsCache.get('labs');
return labsConfig && labsConfig[flag] && labsConfig[flag] === true;
};
module.exports.isSet = flagIsSet;
labs.enabledHelper = function enabledHelper(options, callback) {
var errDetails, errString;
if (labs.isSet(options.flagKey) === true) {
// helper is active, use the callback
return callback();
}
// Else, the helper is not active and we need to handle this as an error
errDetails = {
message: i18n.t('warnings.helpers.helperNotAvailable', {helperName: options.helperName}),
context: i18n.t('warnings.helpers.flagMustBeEnabled', {
helperName: options.helperName,
flagName: options.flagName
}),
help: i18n.t('warnings.helpers.seeLink', {url: options.helpUrl})
};
logging.error(new errors.GhostError(errDetails));
errString = new hbs.handlebars.SafeString(
'<script>console.error("' + _.values(errDetails).join(' ') + '");</script>'
);
if (options.async) {
return Promise.resolve(function asyncError() {
return errString;
});
}
return errString;
};

View file

@ -1,11 +1,8 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
hbs = require('express-hbs'),
utils = require('./utils'),
configUtils = require('../../utils/configUtils'),
helpers = require('../../../server/helpers'),
settingsCache = require('../../../server/settings/cache'),
handlebars = hbs.handlebars,
sandbox = sinon.sandbox.create();
@ -13,7 +10,6 @@ describe('{{asset}} helper', function () {
var rendered, localSettingsCache = {};
before(function () {
utils.loadHelpers();
configUtils.set({assetHash: 'abc'});
sandbox.stub(settingsCache, 'get', function (key) {
@ -26,10 +22,6 @@ describe('{{asset}} helper', function () {
sandbox.restore();
});
it('has loaded asset helper', function () {
should.exist(handlebars.helpers.asset);
});
describe('no subdirectory', function () {
it('handles favicon correctly', function () {
// with ghost set

View file

@ -1,20 +1,9 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{author}} helper', function () {
before(function () {
utils.loadHelpers();
});
it('has loaded author helper', function () {
should.exist(handlebars.helpers.author);
});
it('Returns the link to the author from the context', function () {
var data = {author: {name: 'abc 123', slug: 'abc123', bio: '', website: '', status: '', location: ''}},
result = helpers.author.call(data, {hash: {}});

View file

@ -1,16 +1,12 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
themeList = require('../../../server/themes').list,
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{body_class}} helper', function () {
var options = {};
before(function () {
utils.loadHelpers();
themeList.init({
casper: {
assets: null,
@ -38,10 +34,6 @@ describe('{{body_class}} helper', function () {
themeList.init();
});
it('has loaded body_class helper', function () {
should.exist(handlebars.helpers.body_class);
});
it('can render class string', function () {
options.data.root.context = ['home'];

View file

@ -1,20 +1,9 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{content}} helper', function () {
before(function () {
utils.loadHelpers();
});
it('has loaded content helper', function () {
should.exist(handlebars.helpers.content);
});
it('can render content', function () {
var html = 'Hello World',
rendered = helpers.content.call({html: html});

View file

@ -1,21 +1,10 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
moment = require('moment-timezone');
describe('{{date}} helper', function () {
before(function () {
utils.loadHelpers();
});
it('is loaded', function () {
should.exist(handlebars.helpers.date);
});
it('creates properly formatted date strings', function () {
var testDates = [
'2013-12-31T11:28:58.593+02:00',

View file

@ -1,20 +1,9 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{encode}} helper', function () {
before(function () {
utils.loadHelpers();
});
it('has loaded encode helper', function () {
should.exist(handlebars.helpers.encode);
});
it('can escape URI', function () {
var uri = '$pecial!Charact3r(De[iver]y)Foo #Bar',
expected = '%24pecial!Charact3r(De%5Biver%5Dy)Foo%20%23Bar',

View file

@ -1,20 +1,9 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{excerpt}} Helper', function () {
before(function () {
utils.loadHelpers();
});
it('has loaded excerpt helper', function () {
should.exist(handlebars.helpers.excerpt);
});
it('can render excerpt', function () {
var html = 'Hello World',
rendered = helpers.excerpt.call({html: html});

View file

@ -1,26 +1,15 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{facebook_url}} helper', function () {
var options = {data: {blog: {}}};
before(function () {
utils.loadHelpers();
});
beforeEach(function () {
options.data.blog = {facebook: ''};
});
it('has loaded facebook_url helper', function () {
should.exist(handlebars.helpers.facebook_url);
});
it('should output the facebook url for @blog, if no other facebook username is provided', function () {
options.data.blog = {facebook: 'hey'};

View file

@ -1,11 +1,8 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
_ = require('lodash'),
hbs = require('express-hbs'),
utils = require('./utils'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
sandbox = sinon.sandbox.create();
@ -13,10 +10,6 @@ var should = require('should'),
describe('{{#foreach}} helper', function () {
var options, context, _this, resultData;
before(function () {
utils.loadHelpers();
});
afterEach(function () {
sandbox.restore();
});
@ -42,10 +35,6 @@ describe('{{#foreach}} helper', function () {
helpers.foreach.call(self, context, options);
}
it('is loaded', function () {
should.exist(handlebars.helpers.foreach);
});
it('should not populate data if no private data is supplied (array)', function () {
delete options.data;
options.hash = {
@ -261,7 +250,8 @@ describe('{{#foreach}} helper', function () {
});
describe('(compile)', function () {
var objectHash = {
var handlebars = require('express-hbs').handlebars,
objectHash = {
posts: {
first: {title: 'first'},
second: {title: 'second'},
@ -288,6 +278,10 @@ describe('{{#foreach}} helper', function () {
result.should.eql(expected);
}
before(function () {
handlebars.registerHelper('foreach', helpers.foreach);
});
/** Many of these are copied direct from the handlebars spec */
it('object and @key', function () {
var templateString = '<ul>{{#foreach posts}}<li>{{@key}} {{title}}</li>{{/foreach}}</ul>',

View file

@ -1,11 +1,8 @@
var should = require('should'),
sinon = require('sinon'),
hbs = require('express-hbs'),
Promise = require('bluebird'),
utils = require('./utils'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
api = require('../../../server/api'),
@ -14,24 +11,41 @@ var should = require('should'),
sandbox = sinon.sandbox.create();
describe('{{#get}} helper', function () {
var fn, inverse;
before(function () {
utils.loadHelpers();
});
var fn, inverse, labsStub;
beforeEach(function () {
fn = sandbox.spy();
inverse = sandbox.spy();
sandbox.stub(labs, 'isSet').returns(true);
labsStub = sandbox.stub(labs, 'isSet').returns(true);
});
afterEach(function () {
sandbox.restore();
});
it('has loaded get block helper', function () {
should.exist(handlebars.helpers.get);
it('errors correctly if labs flag not set', function (done) {
labsStub.returns(false);
helpers.get.call(
{},
'posts',
{hash: {}, fn: fn, inverse: inverse}
).then(function (result) {
labsStub.calledOnce.should.be.true();
fn.called.should.be.false();
inverse.called.should.be.false();
should.exist(result);
result.should.be.a.Function();
result().should.be.an.Object().with.property(
'string',
'<script>console.error("The {{get}} helper is not available. ' +
'The Public API labs flag must be enabled if you wish to use the {{get}} helper. ' +
'See http://support.ghost.org/public-api-beta/");</script>'
);
done();
}).catch(done);
});
describe('posts', function () {
@ -42,6 +56,7 @@ describe('{{#get}} helper', function () {
{id: 4, title: 'Test Post 4'}
],
meta = {pagination: {}};
beforeEach(function () {
browsePostsStub = sandbox.stub(api.posts, 'browse');
readPostsStub = sandbox.stub(api.posts, 'read');
@ -67,6 +82,8 @@ describe('{{#get}} helper', function () {
'posts',
{hash: {}, fn: fn, inverse: inverse}
).then(function () {
labsStub.calledOnce.should.be.true();
fn.called.should.be.true();
fn.firstCall.args[0].should.be.an.Object().with.property('posts');
fn.firstCall.args[0].posts.should.eql(testPostsArr);
@ -330,9 +347,6 @@ describe('{{#get}} helper', function () {
});
it('should handle arrays the same as handlebars', function (done) {
var tpl = handlebars.compile('{{post.tags.[0].slug}}'),
output = tpl(data);
helpers.get.call(
data,
'posts',
@ -340,7 +354,7 @@ describe('{{#get}} helper', function () {
).then(function () {
browseStub.firstCall.args.should.be.an.Array().with.lengthOf(1);
browseStub.firstCall.args[0].should.be.an.Object().with.property('filter');
browseStub.firstCall.args[0].filter.should.eql('tags:' + output);
browseStub.firstCall.args[0].filter.should.eql('tags:test');
done();
}).catch(done);

View file

@ -1,36 +1,25 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
Promise = require('bluebird'),
rewire = require('rewire'),
hbs = require('express-hbs'),
utils = require('./utils'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = rewire('../../../server/helpers'),
api = require('../../../server/api'),
helpers = require('../../../server/helpers'),
settingsCache = require('../../../server/settings/cache'),
sandbox = sinon.sandbox.create();
describe('{{ghost_foot}} helper', function () {
before(function () {
utils.loadHelpers();
});
var settingsCacheStub;
afterEach(function () {
sandbox.restore();
});
it('has loaded ghost_foot helper', function () {
should.exist(handlebars.helpers.ghost_foot);
beforeEach(function () {
settingsCacheStub = sandbox.stub(settingsCache, 'get');
});
it('outputs correct injected code', function (done) {
sandbox.stub(api.settings, 'read', function () {
return Promise.resolve({
settings: [{value: '<script type="text/javascript">var test = \'I am a variable!\'</script>'}]
});
});
settingsCacheStub.withArgs('ghost_foot').returns('<script type="text/javascript">var test = \'I am a variable!\'</script>');
helpers.ghost_foot.call().then(function (rendered) {
should.exist(rendered);
@ -39,4 +28,26 @@ describe('{{ghost_foot}} helper', function () {
done();
}).catch(done);
});
it('outputs handles code injection being empty', function (done) {
settingsCacheStub.withArgs('ghost_foot').returns('');
helpers.ghost_foot.call().then(function (rendered) {
should.exist(rendered);
rendered.string.should.eql('');
done();
}).catch(done);
});
it('outputs handles code injection being undefined', function (done) {
settingsCacheStub.withArgs('ghost_foot').returns(undefined);
helpers.ghost_foot.call().then(function (rendered) {
should.exist(rendered);
rendered.string.should.eql('');
done();
}).catch(done);
});
});

View file

@ -1,26 +1,17 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
_ = require('lodash'),
Promise = require('bluebird'),
hbs = require('express-hbs'),
moment = require('moment'),
utils = require('./utils'),
configUtils = require('../../utils/configUtils'),
helpers = require('../../../server/helpers'),
api = require('../../../server/api'),
labs = require('../../../server/utils/labs'),
settingsCache = require('../../../server/settings/cache'),
handlebars = hbs.handlebars,
sandbox = sinon.sandbox.create();
describe('{{ghost_head}} helper', function () {
var settingsReadStub;
before(function () {
utils.loadHelpers();
});
afterEach(function () {
sandbox.restore();
configUtils.restore();
@ -28,12 +19,6 @@ describe('{{ghost_head}} helper', function () {
// TODO: stub `getImageDimensions` to make things faster
beforeEach(function () {
settingsReadStub = sandbox.stub(api.settings, 'read').returns(new Promise.resolve({
settings: [
{value: ''}
]
}));
sandbox.stub(api.clients, 'read').returns(new Promise.resolve({
clients: [
{slug: 'ghost-frontend', secret: 'a1bcde23cfe5', status: 'enabled'}
@ -59,10 +44,6 @@ describe('{{ghost_head}} helper', function () {
configUtils.set('url', 'http://testurl.com/');
});
it('has loaded ghost_head helper', function () {
should.exist(handlebars.helpers.ghost_head);
});
it('returns meta tag string on paginated index page without structured data and schema', function (done) {
helpers.ghost_head.call(
{safeVersion: '0.3', relativeUrl: '/page/2/', context: ['paged', 'index']},
@ -1040,14 +1021,11 @@ describe('{{ghost_head}} helper', function () {
title: 'Ghost',
description: 'blog description',
cover: '/content/images/blog-cover.png',
icon: '/content/images/favicon.png'
icon: '/content/images/favicon.png',
ghost_head: '<style>body {background: red;}</style>'
};
beforeEach(function () {
settingsReadStub.returns(new Promise.resolve({
settings: [{value: '<style>body {background: red;}</style>'}]
}));
sandbox.stub(settingsCache, 'get', function (key) {
return localSettingsCache[key];
});

View file

@ -1,27 +1,16 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
hbs = require('express-hbs'),
utils = require('./utils'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
sandbox = sinon.sandbox.create();
describe('{{#has}} helper', function () {
before(function () {
utils.loadHelpers();
});
afterEach(function () {
sandbox.restore();
});
it('has loaded has block helper', function () {
should.exist(handlebars.helpers.has);
});
it('should handle tag list that validates true', function () {
var fn = sandbox.spy(),
inverse = sandbox.spy();

View file

@ -1,11 +1,8 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
hbs = require('express-hbs'),
utils = require('./utils'),
configUtils = require('../../utils/configUtils'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
sandbox = sinon.sandbox.create();
@ -13,7 +10,6 @@ var should = require('should'),
describe('{{image}} helper', function () {
before(function () {
configUtils.set({url: 'http://testurl.com/'});
utils.loadHelpers();
});
afterEach(function () {
@ -24,10 +20,6 @@ describe('{{image}} helper', function () {
configUtils.restore();
});
it('has loaded image helper', function () {
should.exist(handlebars.helpers.image);
});
it('should output relative url of image', function () {
var rendered = helpers.image.call({
image: '/content/images/image-relative-url.png',

View file

@ -1,26 +1,15 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
hbs = require('express-hbs'),
utils = require('./utils'),
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
logging = require('../../../server/logging'),
sandbox = sinon.sandbox.create();
describe('{{#is}} helper', function () {
before(function () {
utils.loadHelpers();
});
afterEach(function () {
sandbox.restore();
});
it('has loaded is block helper', function () {
should.exist(handlebars.helpers.is);
});
// All positive tests
it('should match single context "index"', function () {
var fn = sandbox.spy(),

View file

@ -1,9 +1,6 @@
var should = require('should'),
sinon = require('sinon'),
hbs = require('express-hbs'),
utils = require('./utils'),
configUtils = require('../../utils/configUtils'),
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
settingsCache = require('../../../server/settings/cache'),
@ -11,8 +8,6 @@ var should = require('should'),
describe('{{meta_description}} helper', function () {
before(function () {
utils.loadHelpers();
sandbox.stub(settingsCache, 'get').returns('Just a blogging platform.');
});
@ -21,10 +16,6 @@ describe('{{meta_description}} helper', function () {
sandbox.restore();
});
it('has loaded meta_description helper', function () {
should.exist(handlebars.helpers.meta_description);
});
it('returns correct blog description', function () {
var rendered = helpers.meta_description.call(
{},

View file

@ -1,9 +1,6 @@
var should = require('should'),
sinon = require('sinon'),
hbs = require('express-hbs'),
utils = require('./utils'),
configUtils = require('../../utils/configUtils'),
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
settingsCache = require('../../../server/settings/cache'),
@ -11,8 +8,6 @@ var should = require('should'),
describe('{{meta_title}} helper', function () {
before(function () {
utils.loadHelpers();
sandbox.stub(settingsCache, 'get', function (key) {
return {
title: 'Ghost'
@ -25,10 +20,6 @@ describe('{{meta_title}} helper', function () {
sandbox.restore();
});
it('has loaded meta_title helper', function () {
should.exist(handlebars.helpers.meta_title);
});
it('returns correct title for homepage', function () {
var rendered = helpers.meta_title.call(
{},

View file

@ -1,11 +1,10 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
configUtils = require('../../utils/configUtils'),
path = require('path'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{navigation}} helper', function () {
@ -17,7 +16,6 @@ describe('{{navigation}} helper', function () {
optionsData;
before(function (done) {
utils.loadHelpers();
hbs.express3({
partialsDir: [configUtils.config.get('paths').helperTemplates]
});
@ -25,6 +23,10 @@ describe('{{navigation}} helper', function () {
hbs.cachePartials(function () {
done();
});
// The navigation partial expects this helper
// @TODO: change to register with Ghost's own registration tools
hbs.registerHelper('url', helpers.url);
});
beforeEach(function () {
@ -40,10 +42,6 @@ describe('{{navigation}} helper', function () {
};
});
it('has loaded navigation helper', function () {
should.exist(handlebars.helpers.navigation);
});
it('should throw errors on invalid data', function () {
// Test 1: navigation = string
optionsData.data.blog.navigation = 'not an object';
@ -187,7 +185,6 @@ describe('{{navigation}} helper with custom template', function () {
var optionsData;
before(function (done) {
utils.loadHelpers();
hbs.express3({
partialsDir: [path.resolve(configUtils.config.get('paths').corePath, 'test/unit/server_helpers/test_tpl')]
});

View file

@ -1,11 +1,7 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
Promise = require('bluebird'),
hbs = require('express-hbs'),
utils = require('./utils'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
api = require('../../../server/api'),
@ -20,7 +16,6 @@ describe('{{next_post}} helper', function () {
describe('with valid post data - ', function () {
beforeEach(function () {
utils.loadHelpers();
readPostStub = sandbox.stub(api.posts, 'read', function (options) {
if (options.include.indexOf('next') === 0) {
return Promise.resolve({
@ -30,10 +25,6 @@ describe('{{next_post}} helper', function () {
});
});
it('has loaded next_post helper', function () {
should.exist(handlebars.helpers.prev_post);
});
it('shows \'if\' template with next post data', function (done) {
var fn = sinon.spy(),
inverse = sinon.spy(),
@ -63,7 +54,6 @@ describe('{{next_post}} helper', function () {
describe('for valid post with no next post', function () {
beforeEach(function () {
utils.loadHelpers();
readPostStub = sandbox.stub(api.posts, 'read', function (options) {
if (options.include.indexOf('next') === 0) {
return Promise.resolve({posts: [{slug: '/current/', title: 'post 2'}]});
@ -95,7 +85,6 @@ describe('{{next_post}} helper', function () {
describe('for invalid post data', function () {
beforeEach(function () {
utils.loadHelpers();
readPostStub = sandbox.stub(api.posts, 'read', function (options) {
if (options.include.indexOf('next') === 0) {
return Promise.resolve({});
@ -121,7 +110,6 @@ describe('{{next_post}} helper', function () {
describe('for unpublished post', function () {
beforeEach(function () {
utils.loadHelpers();
readPostStub = sandbox.stub(api.posts, 'read', function (options) {
if (options.include.indexOf('next') === 0) {
return Promise.resolve({

View file

@ -1,26 +1,15 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{page_url}} helper', function () {
var options = {data: {root: {pagination: {}}}};
before(function () {
utils.loadHelpers();
});
beforeEach(function () {
options.data.root = {pagination: {}};
});
it('has loaded page_url helper', function () {
should.exist(handlebars.helpers.page_url);
});
it('can return a valid url when the relative URL is /', function () {
options.data.root.relativeUrl = '/';
options.data.root.pagination.next = 3;

View file

@ -1,21 +1,22 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
hbs = require('express-hbs'),
utils = require('./utils'),
configUtils = require('../../utils/configUtils'),
path = require('path'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{pagination}} helper', function () {
before(function (done) {
utils.loadHelpers();
hbs.express3({partialsDir: [configUtils.config.get('paths').helperTemplates]});
hbs.cachePartials(function () {
done();
});
// The pagination partial expects this helper
// @TODO: change to register with Ghost's own registration tools
hbs.registerHelper('page_url', helpers.page_url);
});
var paginationRegex = /class="pagination"/,
@ -23,10 +24,6 @@ describe('{{pagination}} helper', function () {
olderRegex = /class="older-posts"/,
pageRegex = /class="page-number"/;
it('has loaded pagination helper', function () {
should.exist(handlebars.helpers.pagination);
});
it('should throw if pagination data is incorrect', function () {
var runHelper = function (data) {
return function () {
@ -126,7 +123,6 @@ describe('{{pagination}} helper', function () {
describe('{{pagination}} helper with custom template', function () {
before(function (done) {
utils.loadHelpers();
hbs.express3({partialsDir: [path.resolve(configUtils.config.get('paths').corePath, 'test/unit/server_helpers/test_tpl')]});
hbs.cachePartials(function () {

View file

@ -1,20 +1,9 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{plural}} helper', function () {
before(function () {
utils.loadHelpers();
});
it('has loaded plural helper', function () {
should.exist(handlebars.helpers.plural);
});
it('will show no-value string', function () {
var expected = 'No Posts',
rendered = helpers.plural.call({}, 0, {

View file

@ -1,20 +1,9 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{post_class}} helper', function () {
before(function () {
utils.loadHelpers();
});
it('has loaded postclass helper', function () {
should.exist(handlebars.helpers.post_class);
});
it('can render class string', function () {
var rendered = helpers.post_class.call({});

View file

@ -1,11 +1,8 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
Promise = require('bluebird'),
hbs = require('express-hbs'),
utils = require('./utils'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
api = require('../../../server/api'),
@ -20,7 +17,6 @@ describe('{{prev_post}} helper', function () {
describe('with valid post data - ', function () {
beforeEach(function () {
utils.loadHelpers();
readPostStub = sandbox.stub(api.posts, 'read', function (options) {
if (options.include.indexOf('previous') === 0) {
return Promise.resolve({
@ -30,10 +26,6 @@ describe('{{prev_post}} helper', function () {
});
});
it('has loaded prev_post helper', function () {
should.exist(handlebars.helpers.prev_post);
});
it('shows \'if\' template with previous post data', function (done) {
var fn = sinon.spy(),
inverse = sinon.spy(),
@ -64,7 +56,6 @@ describe('{{prev_post}} helper', function () {
describe('for valid post with no previous post', function () {
beforeEach(function () {
utils.loadHelpers();
readPostStub = sandbox.stub(api.posts, 'read', function (options) {
if (options.include.indexOf('previous') === 0) {
return Promise.resolve({posts: [{slug: '/current/', title: 'post 2'}]});
@ -97,7 +88,6 @@ describe('{{prev_post}} helper', function () {
describe('for invalid post data', function () {
beforeEach(function () {
utils.loadHelpers();
readPostStub = sandbox.stub(api.posts, 'read', function (options) {
if (options.include.indexOf('previous') === 0) {
return Promise.resolve({});
@ -123,7 +113,6 @@ describe('{{prev_post}} helper', function () {
describe('for unpublished post', function () {
beforeEach(function () {
utils.loadHelpers();
readPostStub = sandbox.stub(api.posts, 'read', function (options) {
if (options.include.indexOf('previous') === 0) {
return Promise.resolve({

View file

@ -1,28 +1,16 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
hbs = require('express-hbs'),
utils = require('./utils'),
rewire = require('rewire'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = rewire('../../../server/helpers'),
helpers = require('../../../server/helpers'),
sandbox = sinon.sandbox.create();
describe('{{tags}} helper', function () {
before(function () {
utils.loadHelpers();
});
afterEach(function () {
sandbox.restore();
});
it('has loaded tags helper', function () {
should.exist(handlebars.helpers.tags);
});
it('can return string with tags', function () {
var tags = [{name: 'foo'}, {name: 'bar'}],
rendered = helpers.tags.call(

View file

@ -1,20 +1,9 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{title}} Helper', function () {
before(function () {
utils.loadHelpers();
});
it('has loaded title helper', function () {
should.exist(handlebars.helpers.title);
});
it('can render title', function () {
var title = 'Hello World',
rendered = helpers.title.call({title: title});

View file

@ -1,26 +1,15 @@
var should = require('should'),
hbs = require('express-hbs'),
utils = require('./utils'),
var should = require('should'), // jshint ignore:line
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers');
describe('{{twitter_url}} helper', function () {
var options = {data: {blog: {}}};
before(function () {
utils.loadHelpers();
});
beforeEach(function () {
options.data.blog = {twitter: ''};
});
it('has loaded twitter_url helper', function () {
should.exist(handlebars.helpers.twitter_url);
});
it('should output the twitter url for @blog, if no other twitter username is provided', function () {
options.data.blog = {twitter: '@hey'};

View file

@ -1,12 +1,9 @@
var should = require('should'),
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
Promise = require('bluebird'),
hbs = require('express-hbs'),
utils = require('./utils'),
configUtils = require('../../utils/configUtils'),
// Stuff we are testing
handlebars = hbs.handlebars,
helpers = require('../../../server/helpers'),
api = require('../../../server/api'),
@ -17,7 +14,6 @@ describe('{{url}} helper', function () {
before(function () {
configUtils.set({url: 'http://testurl.com/'});
utils.loadHelpers();
});
beforeEach(function () {
@ -35,10 +31,6 @@ describe('{{url}} helper', function () {
configUtils.restore();
});
it('has loaded url helper', function () {
should.exist(handlebars.helpers.url);
});
it('should return the slug with a prefix slash if the context is a post', function () {
rendered = helpers.url.call({
html: 'content',

View file

@ -1,20 +0,0 @@
// # Helper Test Utils
//
// Contains shared code for intialising tests
//
// @TODO refactor this file out of existence
// I believe if we refactor the handlebars instances and helpers to be more self-contained and modular
// We can likely have init functions which replace the need for this file
var hbs = require('express-hbs'),
// Stuff we are testing
helpers = require('../../../server/helpers'),
utils = {};
utils.loadHelpers = function () {
var adminHbs = hbs.create();
helpers.loadCoreHelpers(adminHbs);
};
module.exports = utils;

View file

@ -1,34 +1,37 @@
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var should = require('should'),
rewire = require('rewire'),
var should = require('should'), // jshint ignore:line
_ = require('lodash'),
hbs = require('express-hbs'),
// Stuff we are testing
helpers = rewire('../../server/helpers');
helpers = require.main.require('core/server/helpers');
describe('Helpers', function () {
beforeEach(function () {
var adminHbs = hbs.create();
helpers = rewire('../../server/helpers');
helpers.loadCoreHelpers(adminHbs);
});
var hbsHelpers = ['each', 'if', 'unless', 'with', 'helperMissing', 'blockHelperMissing', 'log', 'lookup'],
ghostHelpers = [
'asset', 'author', 'body_class', 'content', 'date', 'encode', 'excerpt', 'facebook_url', 'foreach', 'get',
'ghost_foot', 'ghost_head', 'has', 'image', 'is', 'meta_description', 'meta_title', 'navigation',
'next_post', 'page_url', 'pagination', 'plural', 'post_class', 'prev_post', 'tags', 'title', 'twitter_url',
'url'
],
expectedHelpers = _.concat(hbsHelpers, ghostHelpers);
describe('helperMissing', function () {
it('should not throw an error', function () {
var helperMissing = helpers.__get__('coreHelpers.helperMissing');
describe('Load Core Helpers', function () {
before(function () {
helpers.loadCoreHelpers();
});
should.exist(helperMissing);
// This will work when we finish refactoring
it.skip('should have exactly the right helpers', function () {
var foundHelpers, missingHelpers, unexpectedHelpers;
function runHelper() {
var args = arguments;
return function () {
helperMissing.apply(null, args);
};
}
foundHelpers = _.keys(hbs.handlebars.helpers);
runHelper('test helper').should.not.throwError();
runHelper('test helper', 'second argument').should.not.throwError();
missingHelpers = _.difference(expectedHelpers, foundHelpers);
unexpectedHelpers = _.difference(foundHelpers, expectedHelpers);
missingHelpers.should.be.an.Array().with.lengthOf(0);
unexpectedHelpers.should.be.an.Array().with.lengthOf(0);
});
});
});