diff --git a/Gruntfile.js b/Gruntfile.js index c732eafd7d..dd34e289f3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -10,7 +10,7 @@ var path = require('path'), spawn = require('child_process').spawn, buildDirectory = path.resolve(process.cwd(), '.build'), distDirectory = path.resolve(process.cwd(), '.dist'), - config = require('./core/server/config'), + bootstrap = require('./core/bootstrap'), // ## Build File Patterns @@ -501,7 +501,7 @@ var path = require('path'), grunt.registerTask('loadConfig', function () { var done = this.async(); - config.load().then(function () { + bootstrap().then(function () { done(); }); }); diff --git a/config.example.js b/config.example.js index 0ae1d9184e..b3f5d88e13 100644 --- a/config.example.js +++ b/config.example.js @@ -38,6 +38,9 @@ config = { host: '127.0.0.1', // Port to be passed to node's `net.Server#listen()`, for iisnode set this to `process.env.PORT` port: '2368' + }, + paths: { + contentPath: path.join(__dirname, '/content/') } }, diff --git a/core/server/config/loader.js b/core/bootstrap.js similarity index 91% rename from core/server/config/loader.js rename to core/bootstrap.js index ad7c73ece3..dd6aa519cb 100644 --- a/core/server/config/loader.js +++ b/core/bootstrap.js @@ -7,13 +7,13 @@ var fs = require('fs'), url = require('url'), when = require('when'), - errors = require('../errorHandling'), path = require('path'), - paths = require('./paths'), + errors = require('./server/errorHandling'), + config = require('./server/config'), - appRoot = paths().appRoot, - configExample = paths().configExample, - configFile = process.env.GHOST_CONFIG || paths().config, + appRoot = config().paths.appRoot, + configExample = config().paths.configExample, + configFile = process.env.GHOST_CONFIG || config().paths.config, rejectMessage = 'Unable to load config'; function readConfigFile(envVal) { @@ -112,8 +112,11 @@ function loadConfig() { if (!configExists) { pendingConfig = writeConfigFile(); } - when(pendingConfig).then(validateConfigEnvironment).then(loaded.resolve).otherwise(loaded.reject); + when(pendingConfig).then(validateConfigEnvironment).then(function (rawConfig) { + return config.init(rawConfig).then(loaded.resolve); + }).otherwise(loaded.reject); }); + return loaded.promise; } diff --git a/core/index.js b/core/index.js index 0872f131f2..5413d38f9f 100644 --- a/core/index.js +++ b/core/index.js @@ -2,13 +2,13 @@ // Orchestrates the loading of Ghost // When run from command line. -var config = require('./server/config'), - errors = require('./server/errorHandling'); +var bootstrap = require('./bootstrap'), + errors = require('./server/errorHandling'); process.env.NODE_ENV = process.env.NODE_ENV || 'development'; function startGhost(app) { - config.load().then(function () { + bootstrap().then(function () { var ghost = require('./server'); ghost(app); }).otherwise(errors.logAndThrowError); diff --git a/core/server/api/db.js b/core/server/api/db.js index a29c16e490..645dee5bfe 100644 --- a/core/server/api/db.js +++ b/core/server/api/db.js @@ -7,7 +7,7 @@ var dataExport = require('../data/export'), nodefn = require('when/node/function'), _ = require('lodash'), schema = require('../data/schema').tables, - configPaths = require('../config/paths'), + config = require('../config'), api = {}, db; @@ -20,7 +20,7 @@ db = { /*jslint unparam:true*/ return dataExport().then(function (exportedData) { // Save the exported data to the file system for download - var fileName = path.join(configPaths().exportPath, 'exported-' + (new Date().getTime()) + '.json'); + var fileName = path.join(config().paths.exportPath, 'exported-' + (new Date().getTime()) + '.json'); return nodefn.call(fs.writeFile, fileName, JSON.stringify(exportedData)).then(function () { return when(fileName); @@ -39,7 +39,7 @@ db = { }; return api.notifications.add(notification).then(function () { - res.redirect(configPaths().debugPath); + res.redirect(config().paths.debugPath); }); }); }); diff --git a/core/server/api/index.js b/core/server/api/index.js index 249274f46f..67fc05b290 100644 --- a/core/server/api/index.js +++ b/core/server/api/index.js @@ -31,7 +31,7 @@ function cacheInvalidationHeader(req, result) { } else if (endpoint === 'posts') { cacheInvalidate = "/, /page/*, /rss/, /rss/*"; if (id && jsonResult.slug) { - return config.paths.urlForPost(settings, jsonResult).then(function (postUrl) { + return config.urlForPost(settings, jsonResult).then(function (postUrl) { return cacheInvalidate + ', ' + postUrl; }); } diff --git a/core/server/api/settings.js b/core/server/api/settings.js index 4283f82fc5..bfff1981f1 100644 --- a/core/server/api/settings.js +++ b/core/server/api/settings.js @@ -77,7 +77,7 @@ readSettingsResult = function (result) { settings[member.attributes.key] = val; } })).then(function () { - return when(config.paths().availableThemes).then(function (themes) { + return when(config().paths.availableThemes).then(function (themes) { var themeKeys = Object.keys(themes), res = [], i, diff --git a/core/server/apps/loader.js b/core/server/apps/loader.js index 0573a7fada..f5b67427dc 100644 --- a/core/server/apps/loader.js +++ b/core/server/apps/loader.js @@ -12,7 +12,7 @@ var path = require('path'), function getAppRelativePath(name, relativeTo) { relativeTo = relativeTo || __dirname; - return path.relative(relativeTo, path.join(config.paths().appPath, name)); + return path.relative(relativeTo, path.join(config().paths.appPath, name)); } // Load apps through a psuedo sandbox diff --git a/core/server/config/index.js b/core/server/config/index.js index 798741edca..a67815c876 100644 --- a/core/server/config/index.js +++ b/core/server/config/index.js @@ -3,10 +3,93 @@ // This file itself is a wrapper for the root level config.js file. // All other files that need to reference config.js should use this file. -var loader = require('./loader'), - paths = require('./paths'), +var path = require('path'), + when = require('when'), + url = require('url'), + _ = require('lodash'), + requireTree = require('../require-tree'), theme = require('./theme'), - ghostConfig; + configUrl = require('./url'), + ghostConfig = {}, + appRoot = path.resolve(__dirname, '../../../'), + corePath = path.resolve(appRoot, 'core/'); + +function updateConfig(config) { + var localPath, + contentPath, + subdir; + + // Merge passed in config object onto + // the cached ghostConfig object + _.merge(ghostConfig, config); + + // Protect against accessing a non-existant object. + // This ensures there's always at least a paths object + // because it's referenced in multiple places. + ghostConfig.paths = ghostConfig.paths || {}; + + // Parse local path location + if (ghostConfig.url) { + localPath = url.parse(ghostConfig.url).path; + // Remove trailing slash + if (localPath !== '/') { + localPath = localPath.replace(/\/$/, ''); + } + } + + subdir = localPath === '/' ? '' : localPath; + + // Allow contentPath to be over-written by passed in config object + // Otherwise default to default content path location + contentPath = ghostConfig.paths.contentPath || path.resolve(appRoot, 'content'); + + _.merge(ghostConfig, { + paths: { + 'appRoot': appRoot, + 'subdir': subdir, + 'config': path.join(appRoot, 'config.js'), + 'configExample': path.join(appRoot, 'config.example.js'), + 'corePath': corePath, + + 'contentPath': contentPath, + 'themePath': path.resolve(contentPath, 'themes'), + 'appPath': path.resolve(contentPath, 'apps'), + 'imagesPath': path.resolve(contentPath, 'images'), + 'imagesRelPath': 'content/images', + + 'adminViews': path.join(corePath, '/server/views/'), + 'helperTemplates': path.join(corePath, '/server/helpers/tpl/'), + 'exportPath': path.join(corePath, '/server/data/export/'), + 'lang': path.join(corePath, '/shared/lang/'), + 'debugPath': subdir + '/ghost/debug/', + + 'availableThemes': ghostConfig.paths.availableThemes || [], + 'availableApps': ghostConfig.paths.availableApps || [], + 'builtScriptPath': path.join(corePath, 'built/scripts/') + } + }); + + // Also pass config object to + // configUrl object to maintain + // clean depedency tree + configUrl.setConfig(ghostConfig); + + return ghostConfig; +} + +function initConfig(rawConfig) { + // Cache the config.js object's environment + // object so we can later refer to it. + // Note: this is not the entirety of config.js, + // just the object appropriate for this NODE_ENV + ghostConfig = updateConfig(rawConfig); + + return when.all([requireTree(ghostConfig.paths.themePath), requireTree(ghostConfig.paths.appPath)]).then(function (paths) { + ghostConfig.paths.availableThemes = paths[0]; + ghostConfig.paths.availableApps = paths[1]; + return ghostConfig; + }); +} // Returns NODE_ENV config object function config() { @@ -14,25 +97,18 @@ function config() { // This is currently needed for tests to load config file // successfully. While running application we should never // have to directly delegate to the config.js file. - return ghostConfig || require(paths().config)[process.env.NODE_ENV]; + if (_.isEmpty(ghostConfig)) { + try { + ghostConfig = require(path.resolve(__dirname, '../../../', 'config.js'))[process.env.NODE_ENV] || {}; + } catch (ignore) {/*jslint sloppy: true */} + ghostConfig = updateConfig(ghostConfig); + } + + return ghostConfig; } -function loadConfig() { - return loader().then(function (config) { - // Cache the config.js object's environment - // object so we can later refer to it. - // Note: this is not the entirety of config.js, - // just the object appropriate for this NODE_ENV - ghostConfig = config; - - // can't load theme settings yet as we don't have the API, - // but we can load the paths - return paths.update(config.url); - }); -} - -config.load = loadConfig; -config.paths = paths; -config.theme = theme; - -module.exports = config; \ No newline at end of file +module.exports = config; +module.exports.init = initConfig; +module.exports.theme = theme; +module.exports.urlFor = configUrl.urlFor; +module.exports.urlForPost = configUrl.urlForPost; \ No newline at end of file diff --git a/core/server/config/paths.js b/core/server/config/url.js similarity index 67% rename from core/server/config/paths.js rename to core/server/config/url.js index a1c8f944d5..ac5b39fc4c 100644 --- a/core/server/config/paths.js +++ b/core/server/config/url.js @@ -2,66 +2,17 @@ // the codebase. var moment = require('moment'), - path = require('path'), - when = require('when'), - url = require('url'), _ = require('lodash'), - requireTree = require('../require-tree'), - appRoot = path.resolve(__dirname, '../../../'), - corePath = path.resolve(appRoot, 'core/'), - contentPath = path.resolve(appRoot, 'content/'), - themePath = path.resolve(contentPath + '/themes'), - appPath = path.resolve(contentPath + '/apps'), - themeDirectories = requireTree(themePath), - appDirectories = requireTree(appPath), - localPath = '', - configUrl = '', + ghostConfig = ''; - availableThemes, - availableApps; - - -function paths() { - var subdir = localPath === '/' ? '' : localPath; - - return { - 'appRoot': appRoot, - 'subdir': subdir, - 'config': path.join(appRoot, 'config.js'), - 'configExample': path.join(appRoot, 'config.example.js'), - 'contentPath': contentPath, - 'corePath': corePath, - 'themePath': themePath, - 'appPath': appPath, - 'imagesPath': path.resolve(contentPath, 'images/'), - 'imagesRelPath': 'content/images', - 'adminViews': path.join(corePath, '/server/views/'), - 'helperTemplates': path.join(corePath, '/server/helpers/tpl/'), - 'exportPath': path.join(corePath, '/server/data/export/'), - 'lang': path.join(corePath, '/shared/lang/'), - 'debugPath': subdir + '/ghost/debug/', - 'availableThemes': availableThemes, - 'availableApps': availableApps, - 'builtScriptPath': path.join(corePath, 'built/scripts/') - }; -} - -// TODO: remove configURL and give direct access to config object? -// TODO: not called when executing tests -function update(configURL) { - configUrl = configURL; - localPath = url.parse(configURL).path; - - // Remove trailing slash - if (localPath !== '/') { - localPath = localPath.replace(/\/$/, ''); - } - - return when.all([themeDirectories, appDirectories]).then(function (paths) { - availableThemes = paths[0]; - availableApps = paths[1]; - return; - }); +// ## setConfig +// Simple utility function to allow +// passing of the ghostConfig +// object here to be used locally +// to ensure clean depedency graph +// (i.e. no circular dependencies). +function setConfig(config) { + ghostConfig = config; } // ## createUrl @@ -85,9 +36,9 @@ function createUrl(urlPath, absolute) { // create base of url, always ends without a slash if (absolute) { - output += configUrl.replace(/\/$/, ''); + output += ghostConfig.url.replace(/\/$/, ''); } else { - output += paths().subdir; + output += ghostConfig.paths.subdir; } // append the path, always starts and ends with a slash @@ -186,7 +137,6 @@ function urlForPost(settings, post, absolute) { }); } -module.exports = paths; -module.exports.update = update; +module.exports.setConfig = setConfig; module.exports.urlFor = urlFor; module.exports.urlForPost = urlForPost; diff --git a/core/server/controllers/admin.js b/core/server/controllers/admin.js index 641072400f..1d7de19144 100644 --- a/core/server/controllers/admin.js +++ b/core/server/controllers/admin.js @@ -88,7 +88,7 @@ adminControllers = { req.session.regenerate(function (err) { if (!err) { req.session.user = user.id; - var redirect = config.paths().subdir + '/ghost/'; + var redirect = config().paths.subdir + '/ghost/'; if (req.body.redirect) { redirect += decodeURIComponent(req.body.redirect); } @@ -164,7 +164,7 @@ adminControllers = { if (req.session.user === undefined) { req.session.user = user.id; } - res.json(200, {redirect: config.paths().subdir + '/ghost/'}); + res.json(200, {redirect: config().paths.subdir + '/ghost/'}); } }); }); @@ -206,7 +206,7 @@ adminControllers = { }; return api.notifications.add(notification).then(function () { - res.json(200, {redirect: config.paths().subdir + '/ghost/signin/'}); + res.json(200, {redirect: config().paths.subdir + '/ghost/signin/'}); }); }, function failure(error) { @@ -241,7 +241,7 @@ adminControllers = { errors.logError(err, 'admin.js', "Please check the provided token for validity and expiration."); return api.notifications.add(notification).then(function () { - res.redirect(config.paths().subdir + '/ghost/forgotten'); + res.redirect(config().paths.subdir + '/ghost/forgotten'); }); }); }, @@ -259,7 +259,7 @@ adminControllers = { }; return api.notifications.add(notification).then(function () { - res.json(200, {redirect: config.paths().subdir + '/ghost/signin/'}); + res.json(200, {redirect: config().paths.subdir + '/ghost/signin/'}); }); }).otherwise(function (err) { res.json(401, {error: err.message}); @@ -276,7 +276,7 @@ adminControllers = { }; return api.notifications.add(notification).then(function () { - res.redirect(config.paths().subdir + '/ghost/signin/'); + res.redirect(config().paths.subdir + '/ghost/signin/'); }); }, 'index': function (req, res) { diff --git a/core/server/controllers/frontend.js b/core/server/controllers/frontend.js index 5918ad3b0c..f716f84716 100644 --- a/core/server/controllers/frontend.js +++ b/core/server/controllers/frontend.js @@ -26,7 +26,7 @@ frontendControllers = { // No negative pages, or page 1 if (isNaN(pageParam) || pageParam < 1 || (pageParam === 1 && req.route.path === '/page/:page/')) { - return res.redirect(config.paths().subdir + '/'); + return res.redirect(config().paths.subdir + '/'); } return api.settings.read('postsPerPage').then(function (postPP) { @@ -51,7 +51,7 @@ frontendControllers = { // If page is greater than number of pages we have, redirect to last page if (pageParam > maxPage) { - return res.redirect(maxPage === 1 ? config.paths().subdir + '/' : (config.paths().subdir + '/page/' + maxPage + '/')); + return res.redirect(maxPage === 1 ? config().paths.subdir + '/' : (config().paths.subdir + '/page/' + maxPage + '/')); } // Render the page of posts @@ -78,12 +78,12 @@ frontendControllers = { function render() { // If we're ready to render the page but the last param is 'edit' then we'll send you to the edit page. if (req.params[2] && req.params[2] === 'edit') { - return res.redirect(config.paths().subdir + '/ghost/editor/' + post.id + '/'); + return res.redirect(config().paths.subdir + '/ghost/editor/' + post.id + '/'); } filters.doFilter('prePostsRender', post).then(function (post) { api.settings.read('activeTheme').then(function (activeTheme) { - var paths = config.paths().availableThemes[activeTheme.value], + var paths = config().paths.availableThemes[activeTheme.value], view = post.page && paths.hasOwnProperty('page') ? 'page' : 'post'; res.render(view, {post: post}); }); @@ -134,7 +134,7 @@ frontendControllers = { // No negative pages, or page 1 if (isNaN(pageParam) || pageParam < 1 || (pageParam === 1 && req.route.path === '/rss/:page/')) { - return res.redirect(config.paths().subdir + '/rss/'); + return res.redirect(config().paths.subdir + '/rss/'); } // TODO: needs refactor for multi user to not use first user as default @@ -148,8 +148,8 @@ frontendControllers = { title = result[1].value.value, description = result[2].value.value, permalinks = result[3].value, - siteUrl = config.paths.urlFor('home', null, true), - feedUrl = config.paths.urlFor('rss', null, true); + siteUrl = config.urlFor('home', null, true), + feedUrl = config.urlFor('rss', null, true); feed = new RSS({ title: title, @@ -172,7 +172,7 @@ frontendControllers = { // If page is greater than number of pages we have, redirect to last page if (pageParam > maxPage) { - return res.redirect(config.paths().subdir + '/rss/' + maxPage + '/'); + return res.redirect(config().paths.subdir + '/rss/' + maxPage + '/'); } filters.doFilter('prePostsRender', page.posts).then(function (posts) { @@ -181,7 +181,7 @@ frontendControllers = { item = { title: _.escape(post.title), guid: post.uuid, - url: config.paths.urlFor('post', {post: post, permalinks: permalinks}, true), + url: config.urlFor('post', {post: post, permalinks: permalinks}, true), date: post.published_at, categories: _.pluck(post.tags, 'name'), author: user ? user.name : null diff --git a/core/server/errorHandling.js b/core/server/errorHandling.js index 4ba7d7d413..881a562fb7 100644 --- a/core/server/errorHandling.js +++ b/core/server/errorHandling.js @@ -2,15 +2,15 @@ var _ = require('lodash'), colors = require('colors'), fs = require('fs'), - configPaths = require('./config/paths'), + config = require('./config'), path = require('path'), when = require('when'), hbs = require('express-hbs'), errors, // Paths for views - defaultErrorTemplatePath = path.resolve(configPaths().adminViews, 'user-error.hbs'), - userErrorTemplatePath = path.resolve(configPaths().themePath, 'error.hbs'), + defaultErrorTemplatePath = path.resolve(config().paths.adminViews, 'user-error.hbs'), + userErrorTemplatePath = path.resolve(config().paths.themePath, 'error.hbs'), userErrorTemplateExists = false, ONE_HOUR_S = 60 * 60; @@ -20,7 +20,7 @@ var _ = require('lodash'), */ errors = { updateActiveTheme: function (activeTheme, hasErrorTemplate) { - userErrorTemplatePath = path.resolve(configPaths().themePath, activeTheme, 'error.hbs'); + userErrorTemplatePath = path.resolve(config().paths.themePath, activeTheme, 'error.hbs'); userErrorTemplateExists = hasErrorTemplate; }, diff --git a/core/server/helpers/index.js b/core/server/helpers/index.js index 3f7e6a2b2f..33551e1a79 100644 --- a/core/server/helpers/index.js +++ b/core/server/helpers/index.js @@ -92,7 +92,7 @@ coreHelpers.encode = function (context, str) { // coreHelpers.pageUrl = function (context, block) { /*jslint unparam:true*/ - return config.paths().subdir + (context === 1 ? '/' : ('/page/' + context + '/')); + return config().paths.subdir + (context === 1 ? '/' : ('/page/' + context + '/')); }; // ### URL helper @@ -108,10 +108,10 @@ coreHelpers.url = function (options) { var absolute = options && options.hash.absolute; if (schema.isPost(this)) { - return config.paths.urlForPost(api.settings, this, absolute); + return config.urlForPost(api.settings, this, absolute); } - return when(config.paths.urlFor(this, absolute)); + return when(config.urlFor(this, absolute)); }; // ### Asset helper @@ -125,7 +125,7 @@ coreHelpers.asset = function (context, options) { var output = '', isAdmin = options && options.hash && options.hash.ghost; - output += config.paths().subdir + '/'; + output += config().paths.subdir + '/'; if (!context.match(/^favicon\.ico$/) && !context.match(/^shared/) && !context.match(/^asset/)) { if (isAdmin) { @@ -278,7 +278,7 @@ coreHelpers.ghostScriptTags = function () { scriptList = _.map(scriptList, function (fileName) { return scriptTemplate({ - source: config.paths().subdir + '/ghost/scripts/' + fileName, + source: config().paths.subdir + '/ghost/scripts/' + fileName, version: coreHelpers.assetHash }); }); @@ -356,7 +356,7 @@ coreHelpers.ghost_head = function (options) { head.push(''); head.push(''); + + _.escape(blog.title) + '" href="' + config.urlFor('rss') + '">'); return coreHelpers.url.call(self, {hash: {absolute: true}}).then(function (url) { head.push(''); @@ -373,7 +373,7 @@ coreHelpers.ghost_foot = function (options) { var foot = []; foot.push(scriptTemplate({ - source: config.paths().subdir + '/shared/vendor/jquery/jquery.js', + source: config().paths.subdir + '/shared/vendor/jquery/jquery.js', version: coreHelpers.assetHash })); @@ -559,7 +559,7 @@ coreHelpers.adminUrl = function (options) { // Ghost isn't a named route as currently it violates the must start-and-end with slash rule context = !options || !options.hash || !options.hash.frontend ? {relativeUrl: '/ghost'} : 'home'; - return config.paths.urlFor(context, absolute); + return config.urlFor(context, absolute); }; coreHelpers.updateNotification = function (options) { diff --git a/core/server/index.js b/core/server/index.js index 4fd4250b01..1fc3e6021a 100644 --- a/core/server/index.js +++ b/core/server/index.js @@ -75,7 +75,7 @@ function initDbHashAndFirstRun() { // any are missing. function builtFilesExist() { var deferreds = [], - location = config.paths().builtScriptPath, + location = config().paths.builtScriptPath, fileNames = process.env.NODE_ENV === 'production' ? helpers.scriptFiles.production : helpers.scriptFiles.development; @@ -158,7 +158,7 @@ function setup(server) { server.set('view engine', 'hbs'); // Create a hbs instance for admin and init view engine - server.set('admin view engine', adminHbs.express3({partialsDir: config.paths().adminViews + 'partials'})); + server.set('admin view engine', adminHbs.express3({partialsDir: config().paths.adminViews + 'partials'})); // Load helpers helpers.loadCoreHelpers(adminHbs, assetHash); diff --git a/core/server/middleware/index.js b/core/server/middleware/index.js index 94ad640f16..8bc11407c4 100644 --- a/core/server/middleware/index.js +++ b/core/server/middleware/index.js @@ -35,7 +35,7 @@ function ghostLocals(req, res, next) { res.locals = res.locals || {}; res.locals.version = packageInfo.version; // relative path from the URL, not including subdir - res.locals.relativeUrl = req.path.replace(config.paths().subdir, ''); + res.locals.relativeUrl = req.path.replace(config().paths.subdir, ''); if (res.isAdmin) { res.locals.csrfToken = req.csrfToken(); @@ -79,10 +79,10 @@ function initViews(req, res, next) { if (!res.isAdmin) { hbs.updateTemplateOptions({ data: {blog: config.theme()} }); expressServer.engine('hbs', expressServer.get('theme view engine')); - expressServer.set('views', path.join(config.paths().themePath, expressServer.get('activeTheme'))); + expressServer.set('views', path.join(config().paths.themePath, expressServer.get('activeTheme'))); } else { expressServer.engine('hbs', expressServer.get('admin view engine')); - expressServer.set('views', config.paths().adminViews); + expressServer.set('views', config().paths.adminViews); } next(); @@ -92,9 +92,9 @@ function initViews(req, res, next) { // Helper for manageAdminAndTheme function activateTheme(activeTheme) { var hbsOptions, - themePartials = path.join(config.paths().themePath, activeTheme, 'partials'), + themePartials = path.join(config().paths.themePath, activeTheme, 'partials'), stackLocation = _.indexOf(expressServer.stack, _.find(expressServer.stack, function (stackItem) { - return stackItem.route === config.paths().subdir && stackItem.handle.name === 'settingEnabled'; + return stackItem.route === config().paths.subdir && stackItem.handle.name === 'settingEnabled'; })); // clear the view cache @@ -107,7 +107,7 @@ function activateTheme(activeTheme) { } // set view engine - hbsOptions = { partialsDir: [ config.paths().helperTemplates ] }; + hbsOptions = { partialsDir: [ config().paths.helperTemplates ] }; fs.stat(themePartials, function (err, stats) { // Check that the theme has a partials directory before trying to use it @@ -119,14 +119,14 @@ function activateTheme(activeTheme) { expressServer.set('theme view engine', hbs.express3(hbsOptions)); // Update user error template - errors.updateActiveTheme(activeTheme, config.paths().availableThemes[activeTheme].hasOwnProperty('error')); + errors.updateActiveTheme(activeTheme, config().paths.availableThemes[activeTheme].hasOwnProperty('error')); } // ### ManageAdminAndTheme Middleware // Uses the URL to detect whether this response should be an admin response // This is used to ensure the right content is served, and is not for security purposes function manageAdminAndTheme(req, res, next) { - res.isAdmin = req.url.lastIndexOf(config.paths().subdir + '/ghost/', 0) === 0; + res.isAdmin = req.url.lastIndexOf(config().paths.subdir + '/ghost/', 0) === 0; if (res.isAdmin) { expressServer.enable('admin'); @@ -139,7 +139,7 @@ function manageAdminAndTheme(req, res, next) { // Check if the theme changed if (activeTheme.value !== expressServer.get('activeTheme')) { // Change theme - if (!config.paths().availableThemes.hasOwnProperty(activeTheme.value)) { + if (!config().paths.availableThemes.hasOwnProperty(activeTheme.value)) { if (!res.isAdmin) { // Throw an error if the theme is not available, but not on the admin UI return errors.throwError('The currently active theme ' + activeTheme.value + ' is missing.'); @@ -162,7 +162,7 @@ function redirectToSignup(req, res, next) { /*jslint unparam:true*/ api.users.browse().then(function (users) { if (users.length === 0) { - return res.redirect(config.paths().subdir + '/ghost/signup/'); + return res.redirect(config().paths.subdir + '/ghost/signup/'); } next(); }).otherwise(function (err) { @@ -196,8 +196,8 @@ function checkSSL(req, res, next) { } module.exports = function (server, dbHash) { - var subdir = config.paths().subdir, - corePath = config.paths().corePath, + var subdir = config().paths.subdir, + corePath = config().paths.corePath, cookie; // Cache express server instance diff --git a/core/server/middleware/middleware.js b/core/server/middleware/middleware.js index 797027173c..39a0bbab5a 100644 --- a/core/server/middleware/middleware.js +++ b/core/server/middleware/middleware.js @@ -47,7 +47,7 @@ var middleware = { } redirect = '?r=' + encodeURIComponent(reqPath); } - return res.redirect(config.paths().subdir + '/ghost/signin/' + redirect); + return res.redirect(config().paths.subdir + '/ghost/signin/' + redirect); }); } next(); @@ -68,7 +68,7 @@ var middleware = { // Login and signup forms in particular redirectToDashboard: function (req, res, next) { if (req.session.user) { - return res.redirect(config.paths().subdir + '/ghost/'); + return res.redirect(config().paths.subdir + '/ghost/'); } next(); @@ -140,7 +140,7 @@ var middleware = { forwardToExpressStatic: function (req, res, next) { api.settings.read('activeTheme').then(function (activeTheme) { // For some reason send divides the max age number by 1000 - express['static'](path.join(config.paths().themePath, activeTheme.value), {maxAge: ONE_HOUR_MS})(req, res, next); + express['static'](path.join(config().paths.themePath, activeTheme.value), {maxAge: ONE_HOUR_MS})(req, res, next); }); }, diff --git a/core/server/routes/admin.js b/core/server/routes/admin.js index 2948f2d7c9..a87f15525b 100644 --- a/core/server/routes/admin.js +++ b/core/server/routes/admin.js @@ -3,7 +3,7 @@ var admin = require('../controllers/admin'), middleware = require('../middleware').middleware; module.exports = function (server) { - var subdir = config.paths().subdir; + var subdir = config().paths.subdir; // ### Admin routes server.get('/logout/', function redirect(req, res) { /*jslint unparam:true*/ diff --git a/core/server/storage/localfilesystem.js b/core/server/storage/localfilesystem.js index 238369f8de..5126811972 100644 --- a/core/server/storage/localfilesystem.js +++ b/core/server/storage/localfilesystem.js @@ -8,7 +8,7 @@ var _ = require('lodash'), path = require('path'), when = require('when'), errors = require('../errorHandling'), - configPaths = require('../config/paths'), + config = require('../config'), baseStore = require('./base'), localFileStore; @@ -20,7 +20,7 @@ localFileStore = _.extend(baseStore, { // - returns a promise which ultimately returns the full url to the uploaded image 'save': function (image) { var saved = when.defer(), - targetDir = this.getTargetDir(configPaths().imagesPath), + targetDir = this.getTargetDir(config().paths.imagesPath), targetFilename; this.getUniqueFileName(this, image, targetDir).then(function (filename) { @@ -33,7 +33,7 @@ localFileStore = _.extend(baseStore, { }).then(function () { // The src for the image must be in URI format, not a file system path, which in Windows uses \ // For local file system storage can use relative path so add a slash - var fullUrl = (configPaths().subdir + '/' + path.relative(configPaths().appRoot, targetFilename)).replace(new RegExp('\\' + path.sep, 'g'), '/'); + var fullUrl = (config().paths.subdir + '/' + path.relative(config().paths.appRoot, targetFilename)).replace(new RegExp('\\' + path.sep, 'g'), '/'); return saved.resolve(fullUrl); }).otherwise(function (e) { errors.logError(e); @@ -60,7 +60,7 @@ localFileStore = _.extend(baseStore, { ONE_YEAR_MS = 365 * 24 * ONE_HOUR_MS; // For some reason send divides the max age number by 1000 - return express['static'](configPaths().imagesPath, {maxAge: ONE_YEAR_MS}); + return express['static'](config().paths.imagesPath, {maxAge: ONE_YEAR_MS}); } }); diff --git a/core/shared/lang/i18n.js b/core/shared/lang/i18n.js index ec7dca9afa..394a82b85d 100644 --- a/core/shared/lang/i18n.js +++ b/core/shared/lang/i18n.js @@ -10,7 +10,7 @@ I18n = function (ghost) { // TODO: validate var lang = ghost.settings('defaultLang'), - path = config.paths().lang, + path = config().paths.lang, langFilePath = path + lang + '.json'; return function (req, res, next) { diff --git a/core/test/unit/bootstrap_spec.js b/core/test/unit/bootstrap_spec.js new file mode 100644 index 0000000000..17ab83288f --- /dev/null +++ b/core/test/unit/bootstrap_spec.js @@ -0,0 +1,214 @@ +/*globals describe, it, beforeEach, afterEach */ + +var should = require('should'), + sinon = require('sinon'), + when = require('when'), + path = require('path'), + fs = require('fs'), + _ = require('lodash'), + rewire = require("rewire"), + + // Thing we are testing + defaultConfig = require('../../../config.example')[process.env.NODE_ENV], + bootstrap = rewire('../../bootstrap'), + config = rewire('../../server/config'); + +describe('Bootstrap', function () { + var sandbox, + rejectMessage = bootstrap.__get__('rejectMessage'), + overrideConfig = function (newConfig) { + bootstrap.__set__("readConfigFile", sandbox.stub().returns( + _.extend({}, defaultConfig, newConfig) + )); + }; + + + + beforeEach(function () { + sandbox = sinon.sandbox.create(); + }); + + afterEach(function () { + bootstrap = rewire('../../bootstrap'); + sandbox.restore(); + + }); + + it('loads the config file if one exists', function (done) { + // the test infrastructure is setup so that there is always config present, + // but we want to overwrite the test to actually load config.example.js, so that any local changes + // don't break the tests + bootstrap.__set__("configFile", path.join(config().paths.appRoot, 'config.example.js')); + + bootstrap().then(function (config) { + config.url.should.equal(defaultConfig.url); + config.database.client.should.equal(defaultConfig.database.client); + config.database.connection.should.eql(defaultConfig.database.connection); + config.server.host.should.equal(defaultConfig.server.host); + config.server.port.should.equal(defaultConfig.server.port); + + done(); + }).then(null, done); + }); + + it('creates the config file if one does not exist', function (done) { + + var deferred = when.defer(), + // trick bootstrap into thinking that the config file doesn't exist yet + existsStub = sandbox.stub(fs, 'exists', function (file, cb) { return cb(false); }), + // create a method which will return a pre-resolved promise + resolvedPromise = sandbox.stub().returns(deferred.promise); + + deferred.resolve(); + + // ensure that the file creation is a stub, the tests shouldn't really create a file + bootstrap.__set__("writeConfigFile", resolvedPromise); + bootstrap.__set__("validateConfigEnvironment", resolvedPromise); + + bootstrap().then(function () { + existsStub.calledOnce.should.be.true; + resolvedPromise.calledTwice.should.be.true; + done(); + }).then(null, done); + }); + + it('accepts valid urls', function (done) { + // replace the config file with invalid data + overrideConfig({url: 'http://testurl.com'}); + + bootstrap().then(function (localConfig) { + localConfig.url.should.equal('http://testurl.com'); + + // Next test + overrideConfig({url: 'https://testurl.com'}); + return bootstrap(); + }).then(function (localConfig) { + localConfig.url.should.equal('https://testurl.com'); + + // Next test + overrideConfig({url: 'http://testurl.com/blog/'}); + return bootstrap(); + }).then(function (localConfig) { + localConfig.url.should.equal('http://testurl.com/blog/'); + + // Next test + overrideConfig({url: 'http://testurl.com/ghostly/'}); + return bootstrap(); + }).then(function (localConfig) { + localConfig.url.should.equal('http://testurl.com/ghostly/'); + + // Next test + overrideConfig({url: '//testurl.com'}); + return bootstrap(); + }).then(function (localConfig) { + localConfig.url.should.equal('//testurl.com'); + + done(); + }).then(null, done); + }); + + it('rejects invalid urls', function (done) { + // replace the config file with invalid data + overrideConfig({url: 'notvalid'}); + + bootstrap().otherwise(function (error) { + error.should.include(rejectMessage); + + // Next test + overrideConfig({url: 'something.com'}); + return bootstrap(); + }).otherwise(function (error) { + error.should.include(rejectMessage); + + done(); + }).then(function () { + should.fail('no error was thrown when it should have been'); + done(); + }).then(done, null); + }); + + it('does not permit subdirectories named ghost', function (done) { + // replace the config file with invalid data + overrideConfig({url: 'http://testurl.com/ghost/'}); + + bootstrap().otherwise(function (error) { + error.should.include(rejectMessage); + + // Next test + overrideConfig({url: 'http://testurl.com/ghost/blog/'}); + return bootstrap(); + }).otherwise(function (error) { + error.should.include(rejectMessage); + + // Next test + overrideConfig({url: 'http://testurl.com/blog/ghost'}); + return bootstrap(); + }).otherwise(function (error) { + error.should.include(rejectMessage); + + done(); + }).then(function () { + should.fail('no error was thrown when it should have been'); + done(); + }).then(done, null); + }); + + it('requires a database config', function (done) { + // replace the config file with invalid data + overrideConfig({database: null}); + + bootstrap().otherwise(function (error) { + error.should.include(rejectMessage); + + // Next test + overrideConfig({database: {}}); + return bootstrap(); + }).otherwise(function (error) { + error.should.include(rejectMessage); + + done(); + }).then(function () { + should.fail('no error was thrown when it should have been'); + done(); + }).then(done, null); + }); + + + it('requires a socket or a host and port', function (done) { + // replace the config file with invalid data + overrideConfig({server: {socket: 'test'}}); + + bootstrap().then(function (localConfig) { + localConfig.server.socket.should.equal('test'); + + // Next test + overrideConfig({server: null}); + return bootstrap(); + }).otherwise(function (error) { + error.should.include(rejectMessage); + + // Next test + overrideConfig({server: {host: null}}); + return bootstrap(); + }).otherwise(function (error) { + error.should.include(rejectMessage); + + // Next test + overrideConfig({server: {port: null}}); + return bootstrap(); + }).otherwise(function (error) { + error.should.include(rejectMessage); + + // Next test + overrideConfig({server: {host: null, port: null}}); + return bootstrap(); + }).otherwise(function (error) { + error.should.include(rejectMessage); + + done(); + }).then(function () { + should.fail('no error was thrown when it should have been'); + done(); + }).then(done, null); + }); +}); \ No newline at end of file diff --git a/core/test/unit/config_spec.js b/core/test/unit/config_spec.js index 49d8542a47..26c93ea8a2 100644 --- a/core/test/unit/config_spec.js +++ b/core/test/unit/config_spec.js @@ -12,212 +12,12 @@ var should = require('should'), // Thing we are testing defaultConfig = require('../../../config.example')[process.env.NODE_ENV], - loader = rewire('../../server/config/loader'), theme = rewire('../../server/config/theme'), - paths = rewire('../../server/config/paths'); + config = rewire('../../server/config'), + configUpdate = config.__get__('updateConfig'); describe('Config', function () { - describe('Loader', function () { - var sandbox, - rejectMessage = loader.__get__('rejectMessage'), - overrideConfig = function (newConfig) { - loader.__set__("readConfigFile", sandbox.stub().returns( - _.extend({}, defaultConfig, newConfig) - )); - }; - - - - beforeEach(function () { - sandbox = sinon.sandbox.create(); - }); - - afterEach(function () { - loader = rewire('../../server/config/loader'); - sandbox.restore(); - - }); - - it('loads the config file if one exists', function (done) { - // the test infrastructure is setup so that there is always config present, - // but we want to overwrite the test to actually load config.example.js, so that any local changes - // don't break the tests - loader.__set__("configFile", path.join(paths().appRoot, 'config.example.js')); - - loader().then(function (config) { - config.url.should.equal(defaultConfig.url); - config.database.client.should.equal(defaultConfig.database.client); - config.database.connection.should.eql(defaultConfig.database.connection); - config.server.host.should.equal(defaultConfig.server.host); - config.server.port.should.equal(defaultConfig.server.port); - - done(); - }).then(null, done); - }); - - it('creates the config file if one does not exist', function (done) { - - var deferred = when.defer(), - // trick loader into thinking that the config file doesn't exist yet - existsStub = sandbox.stub(fs, 'exists', function (file, cb) { return cb(false); }), - // create a method which will return a pre-resolved promise - resolvedPromise = sandbox.stub().returns(deferred.promise); - - deferred.resolve(); - - // ensure that the file creation is a stub, the tests shouldn't really create a file - loader.__set__("writeConfigFile", resolvedPromise); - loader.__set__("validateConfigEnvironment", resolvedPromise); - - loader().then(function () { - existsStub.calledOnce.should.be.true; - resolvedPromise.calledTwice.should.be.true; - done(); - }).then(null, done); - }); - - it('accepts valid urls', function (done) { - // replace the config file with invalid data - overrideConfig({url: 'http://testurl.com'}); - - loader().then(function (localConfig) { - localConfig.url.should.equal('http://testurl.com'); - - // Next test - overrideConfig({url: 'https://testurl.com'}); - return loader(); - }).then(function (localConfig) { - localConfig.url.should.equal('https://testurl.com'); - - // Next test - overrideConfig({url: 'http://testurl.com/blog/'}); - return loader(); - }).then(function (localConfig) { - localConfig.url.should.equal('http://testurl.com/blog/'); - - // Next test - overrideConfig({url: 'http://testurl.com/ghostly/'}); - return loader(); - }).then(function (localConfig) { - localConfig.url.should.equal('http://testurl.com/ghostly/'); - - // Next test - overrideConfig({url: '//testurl.com'}); - return loader(); - }).then(function (localConfig) { - localConfig.url.should.equal('//testurl.com'); - - done(); - }).then(null, done); - }); - - it('rejects invalid urls', function (done) { - // replace the config file with invalid data - overrideConfig({url: 'notvalid'}); - - loader().otherwise(function (error) { - error.should.include(rejectMessage); - - // Next test - overrideConfig({url: 'something.com'}); - return loader(); - }).otherwise(function (error) { - error.should.include(rejectMessage); - - done(); - }).then(function () { - should.fail('no error was thrown when it should have been'); - done(); - }).then(done, null); - }); - - it('does not permit subdirectories named ghost', function (done) { - // replace the config file with invalid data - overrideConfig({url: 'http://testurl.com/ghost/'}); - - loader().otherwise(function (error) { - error.should.include(rejectMessage); - - // Next test - overrideConfig({url: 'http://testurl.com/ghost/blog/'}); - return loader(); - }).otherwise(function (error) { - error.should.include(rejectMessage); - - // Next test - overrideConfig({url: 'http://testurl.com/blog/ghost'}); - return loader(); - }).otherwise(function (error) { - error.should.include(rejectMessage); - - done(); - }).then(function () { - should.fail('no error was thrown when it should have been'); - done(); - }).then(done, null); - }); - - it('requires a database config', function (done) { - // replace the config file with invalid data - overrideConfig({database: null}); - - loader().otherwise(function (error) { - error.should.include(rejectMessage); - - // Next test - overrideConfig({database: {}}); - return loader(); - }).otherwise(function (error) { - error.should.include(rejectMessage); - - done(); - }).then(function () { - should.fail('no error was thrown when it should have been'); - done(); - }).then(done, null); - }); - - - it('requires a socket or a host and port', function (done) { - // replace the config file with invalid data - overrideConfig({server: {socket: 'test'}}); - - loader().then(function (localConfig) { - localConfig.server.socket.should.equal('test'); - - // Next test - overrideConfig({server: null}); - return loader(); - }).otherwise(function (error) { - error.should.include(rejectMessage); - - // Next test - overrideConfig({server: {host: null}}); - return loader(); - }).otherwise(function (error) { - error.should.include(rejectMessage); - - // Next test - overrideConfig({server: {port: null}}); - return loader(); - }).otherwise(function (error) { - error.should.include(rejectMessage); - - // Next test - overrideConfig({server: {host: null, port: null}}); - return loader(); - }).otherwise(function (error) { - error.should.include(rejectMessage); - - done(); - }).then(function () { - should.fail('no error was thrown when it should have been'); - done(); - }).then(done, null); - }); - }); - describe('Theme', function () { var sandbox, @@ -268,22 +68,20 @@ describe('Config', function () { }); }); - describe('Paths', function () { - var sandbox; + describe('Index', function () { + var defaultContentPath = config().paths.contentPath; - beforeEach(function () { - sandbox = sinon.sandbox.create(); - }); - - afterEach(function (done) { - sandbox.restore(); - paths.update(defaultConfig.url) - .then(done) - .then(null, done); + afterEach(function () { + configUpdate({ + url: defaultConfig.url, + paths: { + contentPath: defaultContentPath + } + }); }); it('should have exactly the right keys', function () { - var pathConfig = paths(); + var pathConfig = config().paths; // This will fail if there are any extra keys pathConfig.should.have.keys( @@ -309,128 +107,113 @@ describe('Config', function () { }); it('should have the correct values for each key', function () { - var pathConfig = paths(), + var pathConfig = config().paths, appRoot = path.resolve(__dirname, '../../../'); pathConfig.should.have.property('appRoot', appRoot); pathConfig.should.have.property('subdir', ''); }); - it('should not return a slash for subdir', function (done) { - paths.update('http://my-ghost-blog.com').then(function () { - paths().should.have.property('subdir', ''); + it('should not return a slash for subdir', function () { + configUpdate({url: 'http://my-ghost-blog.com'}); + config().paths.should.have.property('subdir', ''); - return paths.update('http://my-ghost-blog.com/'); - }).then(function () { - paths().should.have.property('subdir', ''); - - done(); - }).otherwise(done); + configUpdate({url: 'http://my-ghost-blog.com/'}); + config().paths.should.have.property('subdir', ''); }); - it('should handle subdirectories properly', function (done) { - paths.update('http://my-ghost-blog.com/blog').then(function () { - paths().should.have.property('subdir', '/blog'); + it('should handle subdirectories properly', function () { + configUpdate({url: 'http://my-ghost-blog.com/blog'}); + config().paths.should.have.property('subdir', '/blog'); - return paths.update('http://my-ghost-blog.com/blog/'); - }).then(function () { - paths().should.have.property('subdir', '/blog'); + configUpdate({url: 'http://my-ghost-blog.com/blog/'}); + config().paths.should.have.property('subdir', '/blog'); - return paths.update('http://my-ghost-blog.com/my/blog'); - }).then(function () { - paths().should.have.property('subdir', '/my/blog'); + configUpdate({url: 'http://my-ghost-blog.com/my/blog'}); + config().paths.should.have.property('subdir', '/my/blog'); - return paths.update('http://my-ghost-blog.com/my/blog/'); - }).then(function () { - paths().should.have.property('subdir', '/my/blog'); + configUpdate({url: 'http://my-ghost-blog.com/my/blog/'}); + config().paths.should.have.property('subdir', '/my/blog'); + }); - done(); - }).otherwise(done); + it('should set contentPath and sub-directories correctly', function () { + var contentPath = config().paths.appRoot + '/otherContent/'; + + configUpdate({ + paths: { + contentPath: contentPath + } + }); + + config().paths.should.have.property('contentPath', contentPath); + config().paths.should.have.property('themePath', contentPath + 'themes'); + config().paths.should.have.property('appPath', contentPath + 'apps'); + config().paths.should.have.property('imagesPath', contentPath + 'images'); }); }); describe('urlFor', function () { - afterEach(function (done) { - paths.update(defaultConfig.url) - .then(done) - .then(null, done); + afterEach(function () { + configUpdate({url: defaultConfig.url}); }); - it('should return the home url with no options', function (done) { - paths.urlFor().should.equal('/'); - paths.update('http://my-ghost-blog.com/blog').then(function () { - paths.urlFor().should.equal('/blog/'); - - done(); - }); + it('should return the home url with no options', function () { + config.urlFor().should.equal('/'); + configUpdate({url: 'http://my-ghost-blog.com/blog'}); + config.urlFor().should.equal('/blog/'); }); - it('should return home url when asked for', function (done) { + it('should return home url when asked for', function () { var testContext = 'home'; - paths.update('http://my-ghost-blog.com').then(function () { - paths.urlFor(testContext).should.equal('/'); - paths.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/'); + configUpdate({url: 'http://my-ghost-blog.com'}); + config.urlFor(testContext).should.equal('/'); + config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/'); - return paths.update('http://my-ghost-blog.com/blog'); - }).then(function () { - paths.urlFor(testContext).should.equal('/blog/'); - paths.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/'); - - done(); - }); + configUpdate({url: 'http://my-ghost-blog.com/blog'}); + config.urlFor(testContext).should.equal('/blog/'); + config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/'); }); - it('should return rss url when asked for', function (done) { + it('should return rss url when asked for', function () { var testContext = 'rss'; - paths.update('http://my-ghost-blog.com').then(function () { - paths.urlFor(testContext).should.equal('/rss/'); - paths.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/rss/'); - return paths.update('http://my-ghost-blog.com/blog'); - }).then(function () { - paths.urlFor(testContext).should.equal('/blog/rss/'); - paths.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/rss/'); + configUpdate({url: 'http://my-ghost-blog.com'}); + config.urlFor(testContext).should.equal('/rss/'); + config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/rss/'); - done(); - }); + configUpdate({url: 'http://my-ghost-blog.com/blog'}); + config.urlFor(testContext).should.equal('/blog/rss/'); + config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/rss/'); }); - it('should return url for a random path when asked for', function (done) { + it('should return url for a random path when asked for', function () { var testContext = {relativeUrl: '/about/'}; - paths.update('http://my-ghost-blog.com').then(function () { - paths.urlFor(testContext).should.equal('/about/'); - paths.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/about/'); + configUpdate({url: 'http://my-ghost-blog.com'}); + config.urlFor(testContext).should.equal('/about/'); + config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/about/'); - return paths.update('http://my-ghost-blog.com/blog'); - }).then(function () { - paths.urlFor(testContext).should.equal('/blog/about/'); - paths.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/about/'); - - done(); - }); + configUpdate({url: 'http://my-ghost-blog.com/blog'}); + config.urlFor(testContext).should.equal('/blog/about/'); + config.urlFor(testContext, true).should.equal('http://my-ghost-blog.com/blog/about/'); }); - it('should return url for a post when asked for', function (done) { + it('should return url for a post when asked for', function () { var testContext = 'post', testData = {post: testUtils.DataGenerator.Content.posts[2], permalinks: {value: '/:slug/'}}; - paths.update('http://my-ghost-blog.com').then(function () { - paths.urlFor(testContext, testData).should.equal('/short-and-sweet/'); - paths.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/short-and-sweet/'); + configUpdate({url: 'http://my-ghost-blog.com'}); + config.urlFor(testContext, testData).should.equal('/short-and-sweet/'); + config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/short-and-sweet/'); - return paths.update('http://my-ghost-blog.com/blog'); - }).then(function () { - paths.urlFor(testContext, testData).should.equal('/blog/short-and-sweet/'); - paths.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/blog/short-and-sweet/'); - - done(); - }).then(null, done); + configUpdate({url: 'http://my-ghost-blog.com/blog'}); + config.urlFor(testContext, testData).should.equal('/blog/short-and-sweet/'); + config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/blog/short-and-sweet/'); }); - it('should return url for a dated post when asked for', function (done) { + it('should return url for a dated post when asked for', function () { var testContext = 'post', testData = { post: testUtils.DataGenerator.Content.posts[2], @@ -442,17 +225,13 @@ describe('Config', function () { yyyy = today.getFullYear(), postLink = '/' + yyyy + '/' + mm + '/' + dd + '/short-and-sweet/'; - paths.update('http://my-ghost-blog.com').then(function () { - paths.urlFor(testContext, testData).should.equal(postLink); - paths.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com' + postLink); + configUpdate({url: 'http://my-ghost-blog.com'}); + config.urlFor(testContext, testData).should.equal(postLink); + config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com' + postLink); - return paths.update('http://my-ghost-blog.com/blog'); - }).then(function () { - paths.urlFor(testContext, testData).should.equal('/blog' + postLink); - paths.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/blog' + postLink); - - done(); - }).then(null, done); + configUpdate({url: 'http://my-ghost-blog.com/blog'}); + config.urlFor(testContext, testData).should.equal('/blog' + postLink); + config.urlFor(testContext, testData, true).should.equal('http://my-ghost-blog.com/blog' + postLink); }); }); @@ -464,43 +243,40 @@ describe('Config', function () { sandbox = sinon.sandbox.create(); }); - afterEach(function (done) { + afterEach(function () { sandbox.restore(); - paths.update(defaultConfig.url) - .then(done) - .then(null, done); + configUpdate({url: defaultConfig.url}); }); it('should output correct url for post', function (done) { - var settings = {'read': function read() {}}, + var settings = {'read': function read() {}}, settingsStub = sandbox.stub(settings, 'read', function () { return when({value: '/:slug/'}); }), testData = testUtils.DataGenerator.Content.posts[2], postLink = '/short-and-sweet/'; - paths.update('http://my-ghost-blog.com').then(function () { + configUpdate({url: 'http://my-ghost-blog.com'}); - // next test - return paths.urlForPost(settings, testData); - }).then(function (url) { + // next test + config.urlForPost(settings, testData).then(function (url) { url.should.equal(postLink); // next test - return paths.urlForPost(settings, testData, true); + return config.urlForPost(settings, testData, true); }).then(function (url) { url.should.equal('http://my-ghost-blog.com' + postLink); - return paths.update('http://my-ghost-blog.com/blog'); + return configUpdate({url: 'http://my-ghost-blog.com/blog'}); }).then(function () { // next test - return paths.urlForPost(settings, testData); + return config.urlForPost(settings, testData); }).then(function (url) { url.should.equal('/blog' + postLink); // next test - return paths.urlForPost(settings, testData, true); + return config.urlForPost(settings, testData, true); }).then(function (url) { url.should.equal('http://my-ghost-blog.com/blog' + postLink); @@ -521,28 +297,27 @@ describe('Config', function () { yyyy = today.getFullYear(), postLink = '/' + yyyy + '/' + mm + '/' + dd + '/short-and-sweet/'; - paths.update('http://my-ghost-blog.com').then(function () { + configUpdate({url: 'http://my-ghost-blog.com'}); - // next test - return paths.urlForPost(settings, testData); - }).then(function (url) { + // next test + config.urlForPost(settings, testData).then(function (url) { url.should.equal(postLink); // next test - return paths.urlForPost(settings, testData, true); + return config.urlForPost(settings, testData, true); }).then(function (url) { url.should.equal('http://my-ghost-blog.com' + postLink); - return paths.update('http://my-ghost-blog.com/blog'); + return configUpdate({url: 'http://my-ghost-blog.com/blog'}); }).then(function () { // next test - return paths.urlForPost(settings, testData); + return config.urlForPost(settings, testData); }).then(function (url) { url.should.equal('/blog' + postLink); // next test - return paths.urlForPost(settings, testData, true); + return config.urlForPost(settings, testData, true); }).then(function (url) { url.should.equal('http://my-ghost-blog.com/blog' + postLink); @@ -558,28 +333,27 @@ describe('Config', function () { testData = testUtils.DataGenerator.Content.posts[5], postLink = '/static-page-test/'; - paths.update('http://my-ghost-blog.com').then(function () { + configUpdate({url: 'http://my-ghost-blog.com'}); - // next test - return paths.urlForPost(settings, testData); - }).then(function (url) { + // next test + config.urlForPost(settings, testData).then(function (url) { url.should.equal(postLink); // next test - return paths.urlForPost(settings, testData, true); + return config.urlForPost(settings, testData, true); }).then(function (url) { url.should.equal('http://my-ghost-blog.com' + postLink); - return paths.update('http://my-ghost-blog.com/blog'); + return configUpdate({url: 'http://my-ghost-blog.com/blog'}); }).then(function () { // next test - return paths.urlForPost(settings, testData); + return config.urlForPost(settings, testData); }).then(function (url) { url.should.equal('/blog' + postLink); // next test - return paths.urlForPost(settings, testData, true); + return config.urlForPost(settings, testData, true); }).then(function (url) { url.should.equal('http://my-ghost-blog.com/blog' + postLink); diff --git a/core/test/unit/frontend_spec.js b/core/test/unit/frontend_spec.js index 7ada5efb0c..f1c8c99de1 100644 --- a/core/test/unit/frontend_spec.js +++ b/core/test/unit/frontend_spec.js @@ -4,11 +4,11 @@ var assert = require('assert'), should = require('should'), sinon = require('sinon'), when = require('when'), + rewire = require("rewire"), // Stuff we are testing - config = require('../../server/config'), api = require('../../server/api'), - frontend = require('../../server/controllers/frontend'); + frontend = rewire('../../server/controllers/frontend'); describe('Frontend Controller', function () { @@ -19,6 +19,9 @@ describe('Frontend Controller', function () { beforeEach(function () { sandbox = sinon.sandbox.create(); + + // Reset frontend controller for next test + frontend = rewire('../../server/controllers/frontend'); }); afterEach(function () { @@ -79,7 +82,11 @@ describe('Frontend Controller', function () { }); it('Redirects to home if page number is 0 with subdirectory', function () { - sandbox.stub(config, 'paths', function () { return {subdir: '/blog'}; }); + frontend.__set__('config', function() { + return { + paths: {subdir: '/blog'} + }; + }); var req = {params: {page: 0}, route: {path: '/page/:page/'}}; @@ -91,7 +98,11 @@ describe('Frontend Controller', function () { }); it('Redirects to home if page number is 1 with subdirectory', function () { - sandbox.stub(config, 'paths', function () { return {subdir: '/blog'}; }); + frontend.__set__('config', function() { + return { + paths: {subdir: '/blog'} + }; + }); var req = {params: {page: 1}, route: {path: '/page/:page/'}}; @@ -114,7 +125,11 @@ describe('Frontend Controller', function () { }); it('Redirects to last page if page number too big with subdirectory', function (done) { - sandbox.stub(config, 'paths', function () { return {subdir: '/blog'}; }); + frontend.__set__('config', function() { + return { + paths: {subdir: '/blog'} + }; + }); var req = {params: {page: 4}, route: {path: '/page/:page/'}}; @@ -160,8 +175,8 @@ describe('Frontend Controller', function () { 'value': 'casper' })); - sandbox.stub(config, 'paths', function () { - return { + frontend.__set__('config', sandbox.stub().returns({ + 'paths': { 'subdir': '', 'availableThemes': { 'casper': { @@ -172,8 +187,8 @@ describe('Frontend Controller', function () { 'post': '/content/themes/casper/post.hbs' } } - }; - }); + } + })); }); describe('permalink set to slug', function () { @@ -459,7 +474,15 @@ describe('Frontend Controller', function () { describe('rss redirects', function () { var res, - apiUsersStub; + apiUsersStub, + overwriteConfig = function(newConfig) { + var existingConfig = frontend.__get__('config'); + var newConfigModule = function() { + return newConfig; + }; + newConfigModule.urlFor = existingConfig.urlFor; + frontend.__set__('config', newConfigModule); + }; beforeEach(function () { res = { @@ -522,7 +545,7 @@ describe('Frontend Controller', function () { }); it('Redirects to home if page number is 0 with subdirectory', function () { - sandbox.stub(config, 'paths', function () { return {subdir: '/blog'}; }); + overwriteConfig({paths: {subdir: '/blog'}}); var req = {params: {page: 0}, route: {path: '/rss/:page/'}}; @@ -534,7 +557,7 @@ describe('Frontend Controller', function () { }); it('Redirects to home if page number is 1 with subdirectory', function () { - sandbox.stub(config, 'paths', function () { return {subdir: '/blog'}; }); + overwriteConfig({paths: {subdir: '/blog'}}); var req = {params: {page: 1}, route: {path: '/rss/:page/'}}; @@ -557,7 +580,7 @@ describe('Frontend Controller', function () { }); it('Redirects to last page if page number too big with subdirectory', function (done) { - sandbox.stub(config, 'paths', function () { return {subdir: '/blog'}; }); + overwriteConfig({paths: {subdir: '/blog'}}); var req = {params: {page: 4}, route: {path: '/rss/:page/'}}; diff --git a/core/test/unit/mail_spec.js b/core/test/unit/mail_spec.js index 3037a85a33..ed3d2107b6 100644 --- a/core/test/unit/mail_spec.js +++ b/core/test/unit/mail_spec.js @@ -1,15 +1,15 @@ /*globals describe, beforeEach, afterEach, it*/ -var testUtils = require('../utils'), - should = require('should'), - sinon = require('sinon'), - when = require('when'), - - _ = require("lodash"), - cp = require('child_process'), +var should = require('should'), + sinon = require('sinon'), + when = require('when'), + _ = require("lodash"), + cp = require('child_process'), + rewire = require("rewire"), + testUtils = require('../utils'), // Stuff we are testing - defaultConfig = require('../../../config'), - mailer = require('../../server/mail'), + mailer = rewire('../../server/mail'), + defaultConfig = require('../../../config'), SMTP, SENDMAIL, fakeConfig, @@ -39,6 +39,11 @@ SENDMAIL = { }; describe("Mail", function () { + var overrideConfig = function (newConfig) { + mailer.__set__('config', sandbox.stub().returns( + _.extend({}, defaultConfig, newConfig) + )); + }; beforeEach(function () { // Mock config and settings @@ -72,7 +77,7 @@ describe("Mail", function () { }); it('should setup SMTP transport on initialization', function (done) { - fakeConfig[process.env.NODE_ENV].mail = SMTP; + overrideConfig({mail: SMTP}); mailer.init().then(function () { mailer.should.have.property('transport'); mailer.transport.transportType.should.eql('SMTP'); @@ -82,7 +87,7 @@ describe("Mail", function () { }); it('should setup sendmail transport on initialization', function (done) { - fakeConfig[process.env.NODE_ENV].mail = SENDMAIL; + overrideConfig({mail: SENDMAIL}); mailer.init().then(function () { mailer.should.have.property('transport'); mailer.transport.transportType.should.eql('SENDMAIL'); @@ -92,7 +97,7 @@ describe("Mail", function () { }); it('should fallback to sendmail if no config set', function (done) { - fakeConfig[process.env.NODE_ENV].mail = null; + overrideConfig({mail: null}); mailer.init().then(function () { mailer.should.have.property('transport'); mailer.transport.transportType.should.eql('SENDMAIL'); @@ -102,7 +107,7 @@ describe("Mail", function () { }); it('should fallback to sendmail if config is empty', function (done) { - fakeConfig[process.env.NODE_ENV].mail = {}; + overrideConfig({mail: {}}); mailer.init().then(function () { mailer.should.have.property('transport'); mailer.transport.transportType.should.eql('SENDMAIL'); @@ -112,7 +117,7 @@ describe("Mail", function () { }); it('should disable transport if config is empty & sendmail not found', function (done) { - fakeConfig[process.env.NODE_ENV].mail = {}; + overrideConfig({mail: {}}); mailer.detectSendmail.restore(); sandbox.stub(mailer, "detectSendmail", when.reject); mailer.init().then(function () { @@ -122,7 +127,7 @@ describe("Mail", function () { }); it('should disable transport if config is empty & platform is win32', function (done) { - fakeConfig[process.env.NODE_ENV].mail = {}; + overrideConfig({mail: {}}); mailer.detectSendmail.restore(); mailer.isWindows.restore(); sandbox.stub(mailer, 'isWindows', function () { diff --git a/core/test/unit/server_helpers_index_spec.js b/core/test/unit/server_helpers_index_spec.js index a33ba4b1bc..eb75a331e8 100644 --- a/core/test/unit/server_helpers_index_spec.js +++ b/core/test/unit/server_helpers_index_spec.js @@ -1,24 +1,30 @@ /*globals describe, beforeEach, afterEach, it*/ -var testUtils = require('../utils'), - should = require('should'), - sinon = require('sinon'), - when = require('when'), - _ = require('lodash'), - path = require('path'), - rewire = require('rewire'), - api = require('../../server/api'), - hbs = require('express-hbs'), - packageInfo = require('../../../package'), +var testUtils = require('../utils'), + should = require('should'), + sinon = require('sinon'), + when = require('when'), + _ = require('lodash'), + path = require('path'), + rewire = require('rewire'), + api = require('../../server/api'), + hbs = require('express-hbs'), + packageInfo = require('../../../package'), // Stuff we are testing - handlebars = hbs.handlebars, - helpers = rewire('../../server/helpers'), - config = require('../../server/config'); + handlebars = hbs.handlebars, + helpers = rewire('../../server/helpers'), + config = rewire('../../server/config'), + configUpdate = config.__get__('updateConfig'); describe('Core Helpers', function () { var sandbox, - apiStub; + apiStub, + overrideConfig = function (newConfig) { + helpers.__set__('config', function() { + return newConfig; + }); + }; beforeEach(function (done) { var adminHbs = hbs.create(); @@ -28,6 +34,7 @@ describe('Core Helpers', function () { return when({value: 'casper'}); }); + config = helpers.__get__('config'); config.theme = sandbox.stub(config, 'theme', function () { return { title: 'Ghost', @@ -38,7 +45,7 @@ describe('Core Helpers', function () { helpers.loadCoreHelpers(adminHbs); // Load template helpers in handlebars - hbs.express3({ partialsDir: [config.paths().helperTemplates] }); + hbs.express3({ partialsDir: [config().paths.helperTemplates] }); hbs.cachePartials(function () { done(); }); @@ -317,10 +324,8 @@ describe('Core Helpers', function () { // TODO: these tests should be easier to do! var configUrl = config().url; - afterEach(function (done) { - config.paths.update(configUrl).then(function () { - done(); - }).then(null, done); + afterEach(function () { + configUpdate({url: configUrl}); }); it('has loaded ghost_head helper', function () { @@ -328,54 +333,50 @@ describe('Core Helpers', function () { }); it('returns meta tag string', function (done) { - config.paths.update('http://testurl.com/').then(function () { - helpers.ghost_head.call({version: "0.3.0"}).then(function (rendered) { - should.exist(rendered); - rendered.string.should.equal('\n' + - '\n' + - ''); + configUpdate({url: 'http://testurl.com/'}); + helpers.ghost_head.call({version: "0.3.0"}).then(function (rendered) { + should.exist(rendered); + rendered.string.should.equal('\n' + + '\n' + + ''); - done(); - }); + done(); }).then(null, done); }); it('returns meta tag string even if version is invalid', function (done) { - config.paths.update('http://testurl.com/').then(function () { - return helpers.ghost_head.call({version: "0.9"}).then(function (rendered) { - should.exist(rendered); - rendered.string.should.equal('\n' + - '\n' + - ''); + configUpdate({url: 'http://testurl.com/'}); + helpers.ghost_head.call({version: "0.9"}).then(function (rendered) { + should.exist(rendered); + rendered.string.should.equal('\n' + + '\n' + + ''); - done(); - }); + done(); }).then(null, done); }); it('returns correct rss url with subdirectory', function (done) { - config.paths.update('http://testurl.com/blog/').then(function () { - return helpers.ghost_head.call({version: "0.3.0"}).then(function (rendered) { - should.exist(rendered); - rendered.string.should.equal('\n' + - '\n' + - ''); + configUpdate({url: 'http://testurl.com/blog/'}); + helpers.ghost_head.call({version: "0.3.0"}).then(function (rendered) { + should.exist(rendered); + rendered.string.should.equal('\n' + + '\n' + + ''); - done(); - }); + done(); }).then(null, done); }); it('returns canonical URL', function (done) { - config.paths.update('http://testurl.com').then(function () { - return helpers.ghost_head.call({version: "0.3.0", relativeUrl: '/about/'}).then(function (rendered) { - should.exist(rendered); - rendered.string.should.equal('\n' + - '\n' + - ''); + configUpdate({url: 'http://testurl.com'}); + helpers.ghost_head.call({version: "0.3.0", relativeUrl: '/about/'}).then(function (rendered) { + should.exist(rendered); + rendered.string.should.equal('\n' + + '\n' + + ''); - done(); - }); + done(); }).then(null, done); }); }); @@ -448,7 +449,11 @@ describe('Core Helpers', function () { }); it('can return a valid url with subdirectory', function () { - sandbox.stub(config, 'paths', function () { return {'subdir': '/blog'}; }); + helpers.__set__('config', function() { + return { + paths: {'subdir': '/blog'} + }; + }); helpers.pageUrl(1).should.equal('/blog/'); helpers.pageUrl(2).should.equal('/blog/page/2/'); helpers.pageUrl(50).should.equal('/blog/page/50/'); @@ -674,17 +679,19 @@ describe('Core Helpers', function () { describe("asset helper", function () { var rendered, - configStub; + configOriginal; - beforeEach(function () { - // set the asset hash - helpers.assetHash = 'abc'; + before(function() { + configOriginal = helpers.__get__('config'); }); - afterEach(function () { - if (configStub) { - configStub.restore(); - } + after(function() { + helpers.__set__('config', configOriginal); + }); + + beforeEach(function () { + helpers.assetHash = 'abc'; + helpers.__set__('config', configOriginal); }); it('has loaded asset helper', function () { @@ -702,8 +709,8 @@ describe('Core Helpers', function () { should.exist(rendered); String(rendered).should.equal('/favicon.ico'); - configStub = sinon.stub(config, 'paths', function () { - return {'subdir': '/blog'}; + overrideConfig({ + paths: {'subdir': '/blog'} }); // with subdirectory @@ -728,8 +735,8 @@ describe('Core Helpers', function () { should.exist(rendered); String(rendered).should.equal('/shared/asset.js?v=abc'); - configStub = sinon.stub(config, 'paths', function () { - return {'subdir': '/blog'}; + overrideConfig({ + paths: {'subdir': '/blog'} }); // with subdirectory @@ -749,8 +756,8 @@ describe('Core Helpers', function () { should.exist(rendered); String(rendered).should.equal('/ghost/js/asset.js?v=abc'); - configStub = sinon.stub(config, 'paths', function () { - return {'subdir': '/blog'}; + overrideConfig({ + paths: {'subdir': '/blog'} }); // with subdirectory @@ -765,8 +772,8 @@ describe('Core Helpers', function () { should.exist(rendered); String(rendered).should.equal('/assets/js/asset.js?v=abc'); - configStub = sinon.stub(config, 'paths', function () { - return {'subdir': '/blog'}; + overrideConfig({ + paths: {'subdir': '/blog'} }); // with subdirectory @@ -780,18 +787,21 @@ describe('Core Helpers', function () { // ## Admin only helpers describe("ghostScriptTags helper", function () { var rendered, - configStub; + configOriginal; + + before(function() { + configOriginal = helpers.__get__('config'); + }); + + after(function() { + helpers.__set__('config', configOriginal); + }); beforeEach(function () { // set the asset hash helpers = rewire('../../server/helpers'); helpers.assetHash = 'abc'; - }); - - afterEach(function () { - if (configStub) { - configStub.restore(); - } + helpers.__set__('config', configOriginal); }); it('has loaded ghostScriptTags helper', function () { @@ -809,8 +819,8 @@ describe('Core Helpers', function () { '' ); - configStub = sinon.stub(config, 'paths', function () { - return {'subdir': '/blog'}; + overrideConfig({ + paths: {'subdir': '/blog'} }); // with subdirectory @@ -833,8 +843,8 @@ describe('Core Helpers', function () { should.exist(rendered); String(rendered).should.equal(''); - configStub = sinon.stub(config, 'paths', function () { - return {'subdir': '/blog'}; + overrideConfig({ + paths: {'subdir': '/blog'} }); // with subdirectory @@ -848,10 +858,8 @@ describe('Core Helpers', function () { var rendered, configUrl = config().url; - afterEach(function (done) { - config.paths.update(configUrl).then(function () { - done(); - }).then(null, done); + afterEach(function () { + configUpdate({url: configUrl}); }); @@ -861,40 +869,33 @@ describe('Core Helpers', function () { rendered.should.equal('/ghost'); }); - it('should output the path to admin with subdirectory', function (done) { - config.paths.update('http://testurl.com/blog/').then(function () { - rendered = helpers.adminUrl(); - should.exist(rendered); - rendered.should.equal('/blog/ghost'); - done(); - }); + it('should output the path to admin with subdirectory', function () { + configUpdate({url: 'http://testurl.com/blog/'}); + rendered = helpers.adminUrl(); + should.exist(rendered); + rendered.should.equal('/blog/ghost'); }); - it('should output absolute path if absolute is set', function (done) { + it('should output absolute path if absolute is set', function () { // no trailing slash - config.paths.update('http://testurl.com').then(function () { + configUpdate({url: 'http://testurl.com'}); - rendered = helpers.adminUrl({"hash": {absolute: true}}); - should.exist(rendered); - rendered.should.equal('http://testurl.com/ghost'); + rendered = helpers.adminUrl({"hash": {absolute: true}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/ghost'); - // test trailing slash - return config.paths.update('http://testurl.com/'); - }).then(function () { - rendered = helpers.adminUrl({"hash": {absolute: true}}); - should.exist(rendered); - rendered.should.equal('http://testurl.com/ghost'); - done(); - }); + // test trailing slash + configUpdate({url: 'http://testurl.com/'}); + rendered = helpers.adminUrl({"hash": {absolute: true}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/ghost'); }); - it('should output absolute path with subdirectory', function (done) { - config.paths.update('http://testurl.com/blog').then(function () { - rendered = helpers.adminUrl({"hash": {absolute: true}}); - should.exist(rendered); - rendered.should.equal('http://testurl.com/blog/ghost'); - done(); - }); + it('should output absolute path with subdirectory', function () { + configUpdate({url: 'http://testurl.com/blog'}); + rendered = helpers.adminUrl({"hash": {absolute: true}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/blog/ghost'); }); it('should output the path to frontend if frontend is set', function () { @@ -903,39 +904,31 @@ describe('Core Helpers', function () { rendered.should.equal('/'); }); - it('should output the absolute path to frontend if both are set', function (done) { - config.paths.update('http://testurl.com').then(function () { + it('should output the absolute path to frontend if both are set', function () { + configUpdate({url: 'http://testurl.com'}); - rendered = helpers.adminUrl({"hash": {frontend: true, absolute: true}}); - should.exist(rendered); - rendered.should.equal('http://testurl.com/'); + rendered = helpers.adminUrl({"hash": {frontend: true, absolute: true}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/'); - return config.paths.update('http://testurl.com/'); - }).then(function () { - rendered = helpers.adminUrl({"hash": {frontend: true, absolute: true}}); - should.exist(rendered); - rendered.should.equal('http://testurl.com/'); - done(); - }); + configUpdate({url: 'http://testurl.com/'}); + rendered = helpers.adminUrl({"hash": {frontend: true, absolute: true}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/'); }); - it('should output the path to frontend with subdirectory', function (done) { - config.paths.update('http://testurl.com/blog/').then(function () { - - rendered = helpers.adminUrl({"hash": {frontend: true}}); - should.exist(rendered); - rendered.should.equal('/blog/'); - done(); - }); + it('should output the path to frontend with subdirectory', function () { + configUpdate({url: 'http://testurl.com/blog/'}); + rendered = helpers.adminUrl({"hash": {frontend: true}}); + should.exist(rendered); + rendered.should.equal('/blog/'); }); - it('should output the absolute path to frontend with subdirectory', function (done) { - config.paths.update('http://testurl.com/blog/').then(function () { - rendered = helpers.adminUrl({"hash": {frontend: true, absolute: true}}); - should.exist(rendered); - rendered.should.equal('http://testurl.com/blog/'); - done(); - }); + it('should output the absolute path to frontend with subdirectory', function () { + configUpdate({url: 'http://testurl.com/blog/'}); + rendered = helpers.adminUrl({"hash": {frontend: true, absolute: true}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/blog/'); }); }); describe('updateNotification', function () {