mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 22:11:09 +03:00
Merge pull request #1798 from ErisDS/cache-control
Cache control headers & query string asset management
This commit is contained in:
commit
b955f13cc7
@ -9,7 +9,9 @@ var _ = require('underscore'),
|
||||
// Paths for views
|
||||
defaultErrorTemplatePath = path.resolve(configPaths().adminViews, 'user-error.hbs'),
|
||||
userErrorTemplatePath = path.resolve(configPaths().themePath, 'error.hbs'),
|
||||
userErrorTemplateExists;
|
||||
userErrorTemplateExists,
|
||||
|
||||
ONE_HOUR_S = 60 * 60;
|
||||
|
||||
/**
|
||||
* Basic error handling helpers
|
||||
@ -182,6 +184,8 @@ errors = {
|
||||
error404: function (req, res, next) {
|
||||
var message = res.isAdmin && req.session.user ? "No Ghost Found" : "Page Not Found";
|
||||
|
||||
// 404 errors should be briefly cached
|
||||
res.set({'Cache-Control': 'public, max-age=' + ONE_HOUR_S});
|
||||
if (req.method === 'GET') {
|
||||
this.renderErrorPage(404, message, req, res, next);
|
||||
} else {
|
||||
@ -190,6 +194,13 @@ errors = {
|
||||
},
|
||||
|
||||
error500: function (err, req, res, next) {
|
||||
// 500 errors should never be cached
|
||||
res.set({'Cache-Control': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'});
|
||||
|
||||
if (err.status === 404) {
|
||||
return this.error404(req, res, next);
|
||||
}
|
||||
|
||||
if (req.method === 'GET') {
|
||||
if (!err || !(err instanceof Error)) {
|
||||
next();
|
||||
|
@ -1,20 +1,22 @@
|
||||
var _ = require('underscore'),
|
||||
moment = require('moment'),
|
||||
downsize = require('downsize'),
|
||||
path = require('path'),
|
||||
when = require('when'),
|
||||
var downsize = require('downsize'),
|
||||
hbs = require('express-hbs'),
|
||||
moment = require('moment'),
|
||||
path = require('path'),
|
||||
polyglot = require('node-polyglot').instance,
|
||||
template = require('./template'),
|
||||
errors = require('../errorHandling'),
|
||||
models = require('../models'),
|
||||
filters = require('../filters'),
|
||||
packageInfo = require('../../../package.json'),
|
||||
version = packageInfo.version,
|
||||
scriptTemplate = _.template('<script src="<%= source %>?v=<%= version %>"></script>'),
|
||||
isProduction = process.env.NODE_ENV === 'production',
|
||||
_ = require('underscore'),
|
||||
when = require('when'),
|
||||
|
||||
api = require('../api'),
|
||||
config = require('../config'),
|
||||
errors = require('../errorHandling'),
|
||||
filters = require('../filters'),
|
||||
models = require('../models'),
|
||||
template = require('./template'),
|
||||
|
||||
assetTemplate = _.template('<%= source %>?v=<%= version %>'),
|
||||
scriptTemplate = _.template('<script src="<%= source %>?v=<%= version %>"></script>'),
|
||||
isProduction = process.env.NODE_ENV === 'production',
|
||||
|
||||
coreHelpers = {},
|
||||
registerHelpers;
|
||||
|
||||
@ -128,7 +130,6 @@ coreHelpers.url = function (options) {
|
||||
// *Usage example:*
|
||||
// `{{asset "css/screen.css"}}`
|
||||
// `{{asset "css/screen.css" ghost="true"}}`
|
||||
//
|
||||
// Returns the path to the specified asset. The ghost
|
||||
// flag outputs the asset path for the Ghost admin
|
||||
coreHelpers.asset = function (context, options) {
|
||||
@ -137,7 +138,7 @@ coreHelpers.asset = function (context, options) {
|
||||
|
||||
output += config.paths().subdir + '/';
|
||||
|
||||
if (!context.match(/^shared/)) {
|
||||
if (!context.match(/^favicon\.ico$/) && !context.match(/^shared/)) {
|
||||
if (isAdmin) {
|
||||
output += 'ghost/';
|
||||
} else {
|
||||
@ -146,6 +147,14 @@ coreHelpers.asset = function (context, options) {
|
||||
}
|
||||
|
||||
output += context;
|
||||
|
||||
if (!context.match(/^favicon\.ico$/)) {
|
||||
output = assetTemplate({
|
||||
source: output,
|
||||
version: coreHelpers.assetHash
|
||||
});
|
||||
}
|
||||
|
||||
return new hbs.handlebars.SafeString(output);
|
||||
};
|
||||
|
||||
@ -284,8 +293,8 @@ coreHelpers.ghostScriptTags = function () {
|
||||
|
||||
scriptFiles = _.map(scriptFiles, function (fileName) {
|
||||
return scriptTemplate({
|
||||
source: config.paths().subdir + '/built/scripts/' + fileName,
|
||||
version: version
|
||||
source: config.paths().subdir + '/ghost/scripts/' + fileName,
|
||||
version: coreHelpers.assetHash
|
||||
});
|
||||
});
|
||||
|
||||
@ -379,7 +388,7 @@ coreHelpers.ghost_foot = function (options) {
|
||||
|
||||
foot.push(scriptTemplate({
|
||||
source: config.paths().subdir + '/shared/vendor/jquery/jquery.js',
|
||||
version: this.version
|
||||
version: coreHelpers.assetHash
|
||||
}));
|
||||
|
||||
return filters.doFilter('ghost_foot', foot).then(function (foot) {
|
||||
@ -593,11 +602,14 @@ function registerAsyncAdminHelper(name, fn) {
|
||||
|
||||
|
||||
|
||||
registerHelpers = function (adminHbs) {
|
||||
registerHelpers = function (adminHbs, assetHash) {
|
||||
|
||||
// Expose hbs instance for admin
|
||||
coreHelpers.adminHbs = adminHbs;
|
||||
|
||||
// Store hash for assets
|
||||
coreHelpers.assetHash = assetHash;
|
||||
|
||||
|
||||
// Register theme helpers
|
||||
registerThemeHelper('asset', coreHelpers.asset);
|
||||
|
@ -3,30 +3,31 @@
|
||||
// modules to ensure config gets right setting.
|
||||
|
||||
// Module dependencies
|
||||
var config = require('./config'),
|
||||
express = require('express'),
|
||||
when = require('when'),
|
||||
_ = require('underscore'),
|
||||
semver = require('semver'),
|
||||
fs = require('fs'),
|
||||
errors = require('./errorHandling'),
|
||||
plugins = require('./plugins'),
|
||||
path = require('path'),
|
||||
Polyglot = require('node-polyglot'),
|
||||
mailer = require('./mail'),
|
||||
helpers = require('./helpers'),
|
||||
middleware = require('./middleware'),
|
||||
routes = require('./routes'),
|
||||
packageInfo = require('../../package.json'),
|
||||
models = require('./models'),
|
||||
permissions = require('./permissions'),
|
||||
uuid = require('node-uuid'),
|
||||
api = require('./api'),
|
||||
hbs = require('express-hbs'),
|
||||
var crypto = require('crypto'),
|
||||
express = require('express'),
|
||||
hbs = require('express-hbs'),
|
||||
fs = require('fs'),
|
||||
uuid = require('node-uuid'),
|
||||
path = require('path'),
|
||||
Polyglot = require('node-polyglot'),
|
||||
semver = require('semver'),
|
||||
_ = require('underscore'),
|
||||
when = require('when'),
|
||||
|
||||
api = require('./api'),
|
||||
config = require('./config'),
|
||||
errors = require('./errorHandling'),
|
||||
helpers = require('./helpers'),
|
||||
mailer = require('./mail'),
|
||||
middleware = require('./middleware'),
|
||||
models = require('./models'),
|
||||
permissions = require('./permissions'),
|
||||
plugins = require('./plugins'),
|
||||
routes = require('./routes'),
|
||||
packageInfo = require('../../package.json'),
|
||||
|
||||
|
||||
// Variables
|
||||
setup,
|
||||
init,
|
||||
dbHash;
|
||||
|
||||
// If we're in development mode, require "when/console/monitor"
|
||||
@ -79,6 +80,9 @@ function initDbHashAndFirstRun() {
|
||||
// Finally it starts the http server.
|
||||
function setup(server) {
|
||||
|
||||
// create a hash for cache busting assets
|
||||
var assetHash = (crypto.createHash('md5').update(packageInfo.version + Date().now).digest('hex')).substring(0, 10);
|
||||
|
||||
// Set up Polygot instance on the require module
|
||||
Polyglot.instance = new Polyglot();
|
||||
|
||||
@ -112,6 +116,7 @@ function setup(server) {
|
||||
var adminHbs = hbs.create();
|
||||
|
||||
// ##Configuration
|
||||
server.set('version hash', assetHash);
|
||||
|
||||
// return the correct mime type for woff filess
|
||||
express['static'].mime.define({'application/font-woff': ['woff']});
|
||||
@ -124,7 +129,7 @@ function setup(server) {
|
||||
server.set('admin view engine', adminHbs.express3({partialsDir: config.paths().adminViews + 'partials'}));
|
||||
|
||||
// Load helpers
|
||||
helpers.loadCoreHelpers(adminHbs);
|
||||
helpers.loadCoreHelpers(adminHbs, assetHash);
|
||||
|
||||
// ## Middleware
|
||||
middleware(server, dbHash);
|
||||
|
@ -18,7 +18,11 @@ var middleware = require('./middleware'),
|
||||
BSStore = require('../bookshelf-session'),
|
||||
models = require('../models'),
|
||||
|
||||
expressServer;
|
||||
expressServer,
|
||||
ONE_HOUR_S = 60 * 60,
|
||||
ONE_YEAR_S = 365 * 24 * ONE_HOUR_S,
|
||||
ONE_HOUR_MS = ONE_HOUR_S * 1000,
|
||||
ONE_YEAR_MS = 365 * 24 * ONE_HOUR_MS;
|
||||
|
||||
// ##Custom Middleware
|
||||
|
||||
@ -186,9 +190,7 @@ function checkSSL(req, res, next) {
|
||||
}
|
||||
|
||||
module.exports = function (server, dbHash) {
|
||||
var oneHour = 60 * 60 * 1000,
|
||||
oneYear = 365 * 24 * oneHour,
|
||||
subdir = config.paths().subdir,
|
||||
var subdir = config.paths().subdir,
|
||||
corePath = config.paths().corePath,
|
||||
cookie;
|
||||
|
||||
@ -206,16 +208,11 @@ module.exports = function (server, dbHash) {
|
||||
// Favicon
|
||||
expressServer.use(subdir, express.favicon(corePath + '/shared/favicon.ico'));
|
||||
|
||||
// Shared static config
|
||||
expressServer.use(subdir + '/shared', express['static'](path.join(corePath, '/shared')));
|
||||
|
||||
// Static assets
|
||||
// For some reason send divides the max age number by 1000
|
||||
expressServer.use(subdir + '/shared', express['static'](path.join(corePath, '/shared'), {maxAge: ONE_HOUR_MS}));
|
||||
expressServer.use(subdir + '/content/images', storage.get_storage().serve());
|
||||
|
||||
// Serve our built scripts; can't use /scripts here because themes already are
|
||||
expressServer.use(subdir + '/built/scripts', express['static'](path.join(corePath, '/built/scripts'), {
|
||||
// Put a maxAge of one year on built scripts
|
||||
maxAge: oneYear
|
||||
}));
|
||||
expressServer.use(subdir + '/ghost/scripts', express['static'](path.join(corePath, '/built/scripts'), {maxAge: ONE_YEAR_MS}));
|
||||
|
||||
// First determine whether we're serving admin or theme content
|
||||
expressServer.use(manageAdminAndTheme);
|
||||
@ -223,25 +220,27 @@ module.exports = function (server, dbHash) {
|
||||
// Force SSL
|
||||
expressServer.use(checkSSL);
|
||||
|
||||
|
||||
// Admin only config
|
||||
expressServer.use(subdir + '/ghost', middleware.whenEnabled('admin', express['static'](path.join(corePath, '/client/assets'))));
|
||||
expressServer.use(subdir + '/ghost', middleware.whenEnabled('admin', express['static'](path.join(corePath, '/client/assets'), {maxAge: ONE_YEAR_MS})));
|
||||
|
||||
// Theme only config
|
||||
expressServer.use(subdir, middleware.whenEnabled(expressServer.get('activeTheme'), middleware.staticTheme()));
|
||||
|
||||
// Add in all trailing slashes
|
||||
expressServer.use(slashes());
|
||||
expressServer.use(slashes(true, {headers: {'Cache-Control': 'public, max-age=' + ONE_YEAR_S}}));
|
||||
|
||||
// Body parsing
|
||||
expressServer.use(express.json());
|
||||
expressServer.use(express.urlencoded());
|
||||
|
||||
expressServer.use(subdir + '/ghost/upload/', middleware.busboy);
|
||||
expressServer.use(subdir + '/ghost/api/v0.1/db/', middleware.busboy);
|
||||
|
||||
// Session handling
|
||||
// ### Sessions
|
||||
cookie = {
|
||||
path: subdir + '/ghost',
|
||||
maxAge: 12 * oneHour
|
||||
maxAge: 12 * ONE_HOUR_MS
|
||||
};
|
||||
|
||||
// if SSL is forced, add secure flag to cookie
|
||||
@ -258,17 +257,25 @@ module.exports = function (server, dbHash) {
|
||||
cookie: cookie
|
||||
}));
|
||||
|
||||
|
||||
//enable express csrf protection
|
||||
expressServer.use(middleware.conditionalCSRF);
|
||||
|
||||
|
||||
// local data
|
||||
expressServer.use(ghostLocals);
|
||||
// So on every request we actually clean out reduntant passive notifications from the server side
|
||||
// So on every request we actually clean out redundant passive notifications from the server side
|
||||
expressServer.use(middleware.cleanNotifications);
|
||||
|
||||
// Initialise the views
|
||||
expressServer.use(initViews);
|
||||
|
||||
// process the application routes
|
||||
|
||||
// ### Caching
|
||||
expressServer.use(middleware.cacheControl('public'));
|
||||
expressServer.use('/api/', middleware.cacheControl('private'));
|
||||
expressServer.use('/ghost/', middleware.cacheControl('private'));
|
||||
|
||||
// ### Routing
|
||||
expressServer.use(subdir, expressServer.router);
|
||||
|
||||
// ### Error handling
|
||||
|
@ -8,7 +8,9 @@ var _ = require('underscore'),
|
||||
config = require('../config'),
|
||||
path = require('path'),
|
||||
api = require('../api'),
|
||||
expressServer;
|
||||
|
||||
expressServer,
|
||||
ONE_HOUR_MS = 60 * 60 * 1000;
|
||||
|
||||
function isBlackListedFileType(file) {
|
||||
var blackListedFileTypes = ['.hbs', '.md', '.json'],
|
||||
@ -89,16 +91,26 @@ var middleware = {
|
||||
});
|
||||
},
|
||||
|
||||
// ### DisableCachedResult Middleware
|
||||
// Disable any caching until it can be done properly
|
||||
disableCachedResult: function (req, res, next) {
|
||||
// ### CacheControl Middleware
|
||||
// provide sensible cache control headers
|
||||
cacheControl: function (options) {
|
||||
/*jslint unparam:true*/
|
||||
res.set({
|
||||
'Cache-Control': 'no-cache, must-revalidate',
|
||||
'Expires': 'Sat, 26 Jul 1997 05:00:00 GMT'
|
||||
});
|
||||
var profiles = {
|
||||
'public': 'public, max-age=0',
|
||||
'private': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
|
||||
},
|
||||
output;
|
||||
|
||||
next();
|
||||
if (_.isString(options) && profiles.hasOwnProperty(options)) {
|
||||
output = profiles[options];
|
||||
}
|
||||
|
||||
return function cacheControlHeaders(req, res, next) {
|
||||
if (output) {
|
||||
res.set({'Cache-Control': output});
|
||||
}
|
||||
next();
|
||||
};
|
||||
},
|
||||
|
||||
// ### whenEnabled Middleware
|
||||
@ -128,7 +140,8 @@ var middleware = {
|
||||
// to allow unit testing
|
||||
forwardToExpressStatic: function (req, res, next) {
|
||||
api.settings.read('activeTheme').then(function (activeTheme) {
|
||||
express['static'](path.join(config.paths().themePath, activeTheme.value))(req, res, next);
|
||||
// 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);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -5,26 +5,26 @@ module.exports = function (server) {
|
||||
// ### API routes
|
||||
/* TODO: auth should be public auth not user auth */
|
||||
// #### Posts
|
||||
server.get('/ghost/api/v0.1/posts', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.posts.browse));
|
||||
server.post('/ghost/api/v0.1/posts', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.posts.add));
|
||||
server.get('/ghost/api/v0.1/posts/:id', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.posts.read));
|
||||
server.put('/ghost/api/v0.1/posts/:id', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.posts.edit));
|
||||
server.del('/ghost/api/v0.1/posts/:id', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.posts.destroy));
|
||||
server.get('/ghost/api/v0.1/posts', middleware.authAPI, api.requestHandler(api.posts.browse));
|
||||
server.post('/ghost/api/v0.1/posts', middleware.authAPI, api.requestHandler(api.posts.add));
|
||||
server.get('/ghost/api/v0.1/posts/:id', middleware.authAPI, api.requestHandler(api.posts.read));
|
||||
server.put('/ghost/api/v0.1/posts/:id', middleware.authAPI, api.requestHandler(api.posts.edit));
|
||||
server.del('/ghost/api/v0.1/posts/:id', middleware.authAPI, api.requestHandler(api.posts.destroy));
|
||||
// #### Settings
|
||||
server.get('/ghost/api/v0.1/settings/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.settings.browse));
|
||||
server.get('/ghost/api/v0.1/settings/:key/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.settings.read));
|
||||
server.put('/ghost/api/v0.1/settings/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.settings.edit));
|
||||
server.get('/ghost/api/v0.1/settings/', middleware.authAPI, api.requestHandler(api.settings.browse));
|
||||
server.get('/ghost/api/v0.1/settings/:key/', middleware.authAPI, api.requestHandler(api.settings.read));
|
||||
server.put('/ghost/api/v0.1/settings/', middleware.authAPI, api.requestHandler(api.settings.edit));
|
||||
// #### Users
|
||||
server.get('/ghost/api/v0.1/users/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.users.browse));
|
||||
server.get('/ghost/api/v0.1/users/:id/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.users.read));
|
||||
server.put('/ghost/api/v0.1/users/:id/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.users.edit));
|
||||
server.get('/ghost/api/v0.1/users/', middleware.authAPI, api.requestHandler(api.users.browse));
|
||||
server.get('/ghost/api/v0.1/users/:id/', middleware.authAPI, api.requestHandler(api.users.read));
|
||||
server.put('/ghost/api/v0.1/users/:id/', middleware.authAPI, api.requestHandler(api.users.edit));
|
||||
// #### Tags
|
||||
server.get('/ghost/api/v0.1/tags/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.tags.all));
|
||||
server.get('/ghost/api/v0.1/tags/', middleware.authAPI, api.requestHandler(api.tags.all));
|
||||
// #### Notifications
|
||||
server.del('/ghost/api/v0.1/notifications/:id', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.notifications.destroy));
|
||||
server.post('/ghost/api/v0.1/notifications/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.notifications.add));
|
||||
server.del('/ghost/api/v0.1/notifications/:id', middleware.authAPI, api.requestHandler(api.notifications.destroy));
|
||||
server.post('/ghost/api/v0.1/notifications/', middleware.authAPI, api.requestHandler(api.notifications.add));
|
||||
// #### Import/Export
|
||||
server.get('/ghost/api/v0.1/db/', middleware.auth, api.db['export']);
|
||||
server.post('/ghost/api/v0.1/db/', middleware.auth, api.db['import']);
|
||||
server.del('/ghost/api/v0.1/db/', middleware.authAPI, middleware.disableCachedResult, api.requestHandler(api.db.deleteAllContent));
|
||||
server.del('/ghost/api/v0.1/db/', middleware.authAPI, api.requestHandler(api.db.deleteAllContent));
|
||||
};
|
@ -56,7 +56,11 @@ localFileStore = _.extend(baseStore, {
|
||||
|
||||
// middleware for serving the files
|
||||
'serve': function () {
|
||||
return express['static'](configPaths().imagesPath);
|
||||
var ONE_HOUR_MS = 60 * 60 * 1000,
|
||||
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});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*globals casper, __utils__, url, testPost */
|
||||
|
||||
CasperTest.begin("Content screen is correct", 21, function suite(test) {
|
||||
CasperTest.begin("Content screen is correct", 20, function suite(test) {
|
||||
// Create a sample post
|
||||
casper.thenOpen(url + 'ghost/editor/', function testTitleAndUrl() {
|
||||
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
@ -37,10 +37,6 @@ CasperTest.begin("Content screen is correct", 21, function suite(test) {
|
||||
test.assertSelectorHasText("#usermenu .usermenu-profile a", "Your Profile");
|
||||
test.assertSelectorHasText("#usermenu .usermenu-help a", "Help / Support");
|
||||
test.assertSelectorHasText("#usermenu .usermenu-signout a", "Sign Out");
|
||||
|
||||
test.assertResourceExists(function (resource) {
|
||||
return resource.url.match(/user-image\.png$/) && (resource.status === 200 || resource.status === 304);
|
||||
}, 'Default user image');
|
||||
});
|
||||
|
||||
casper.then(function testViews() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*globals casper, __utils__, url */
|
||||
|
||||
CasperTest.begin("Settings screen is correct", 17, function suite(test) {
|
||||
CasperTest.begin("Settings screen is correct", 15, function suite(test) {
|
||||
casper.thenOpen(url + "ghost/settings/", function testTitleAndUrl() {
|
||||
test.assertTitle("Ghost Admin", "Ghost admin has no title");
|
||||
test.assertUrlMatch(/ghost\/settings\/general\/$/, "Ghost doesn't require login this time");
|
||||
@ -32,16 +32,6 @@ CasperTest.begin("Settings screen is correct", 17, function suite(test) {
|
||||
test.assertEval(function testContentIsUser() {
|
||||
return document.querySelector('.settings-content').id === 'user';
|
||||
}, "loaded content is user screen");
|
||||
|
||||
test.assertResourceExists(function (resource) {
|
||||
return resource.url.match(/user-image\.png$/) && (resource.status === 200 || resource.status === 304);
|
||||
}, 'Default user image');
|
||||
|
||||
test.assertResourceExists(function (resource) {
|
||||
return resource.url.match(/user-cover\.png$/) && (resource.status === 200 || resource.status === 304);
|
||||
}, 'Default cover image');
|
||||
|
||||
|
||||
}, function onTimeOut() {
|
||||
test.fail('User screen failed to load');
|
||||
});
|
||||
|
121
core/test/functional/routes/admin_test.js
Normal file
121
core/test/functional/routes/admin_test.js
Normal file
@ -0,0 +1,121 @@
|
||||
/*global describe, it, before, after */
|
||||
|
||||
// # Frontend Route tests
|
||||
// As it stands, these tests depend on the database, and as such are integration tests.
|
||||
// Mocking out the models to not touch the DB would turn these into unit tests, and should probably be done in future,
|
||||
// But then again testing real code, rather than mock code, might be more useful...
|
||||
|
||||
var request = require('supertest'),
|
||||
should = require('should'),
|
||||
moment = require('moment'),
|
||||
|
||||
testUtils = require('../../utils'),
|
||||
config = require('../../../server/config'),
|
||||
|
||||
ONE_HOUR_S = 60 * 60,
|
||||
ONE_YEAR_S = 365 * 24 * ONE_HOUR_S,
|
||||
cacheRules = {
|
||||
'public': 'public, max-age=0',
|
||||
'hour': 'public, max-age=' + ONE_HOUR_S,
|
||||
'year': 'public, max-age=' + ONE_YEAR_S,
|
||||
'private': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
|
||||
};
|
||||
|
||||
describe('Admin Routing', function () {
|
||||
function doEnd(done) {
|
||||
return function (err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
should.not.exist(res.headers['x-cache-invalidate']);
|
||||
should.not.exist(res.headers['X-CSRF-Token']);
|
||||
should.exist(res.headers['set-cookie']);
|
||||
should.exist(res.headers.date);
|
||||
|
||||
done();
|
||||
};
|
||||
}
|
||||
|
||||
before(function (done) {
|
||||
testUtils.clearData().then(function () {
|
||||
// we initialise data, but not a user. No user should be required for navigating the frontend
|
||||
return testUtils.initData();
|
||||
}).then(function () {
|
||||
done();
|
||||
}, done);
|
||||
|
||||
// Setup the request object with the correct URL
|
||||
request = request(config().url);
|
||||
});
|
||||
|
||||
describe('Ghost Admin Signup', function () {
|
||||
it('should have a session cookie which expires in 12 hours', function (done) {
|
||||
request.get('/ghost/signup/')
|
||||
.end(function firstRequest(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
should.not.exist(res.headers['x-cache-invalidate']);
|
||||
should.not.exist(res.headers['X-CSRF-Token']);
|
||||
should.exist(res.headers['set-cookie']);
|
||||
should.exist(res.headers.date);
|
||||
|
||||
var expires;
|
||||
// Session should expire 12 hours after the time in the date header
|
||||
expires = moment(res.headers.date).add('Hours', 12).format("ddd, DD MMM YYYY HH:mm");
|
||||
expires = new RegExp("Expires=" + expires);
|
||||
|
||||
res.headers['set-cookie'].should.match(expires);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should redirect from /ghost to /ghost/signup when no user', function (done) {
|
||||
request.get('/ghost/')
|
||||
.expect('Location', /ghost\/signup/)
|
||||
.expect('Cache-Control', cacheRules['private'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should redirect from /ghost/signin to /ghost/signup when no user', function (done) {
|
||||
request.get('/ghost/signin/')
|
||||
.expect('Location', /ghost\/signup/)
|
||||
.expect('Cache-Control', cacheRules['private'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should respond with html for /ghost/signup', function (done) {
|
||||
request.get('/ghost/signup/')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Cache-Control', cacheRules['private'])
|
||||
.expect(200)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
// Add user
|
||||
|
||||
// it('should redirect from /ghost/signup to /ghost/signin with user', function (done) {
|
||||
// done();
|
||||
// });
|
||||
|
||||
// it('should respond with html for /ghost/signin', function (done) {
|
||||
// done();
|
||||
// });
|
||||
|
||||
// Do Login
|
||||
|
||||
// it('should redirect from /ghost/signup to /ghost/ when logged in', function (done) {
|
||||
// done();
|
||||
// });
|
||||
|
||||
// it('should redirect from /ghost/signup to /ghost/ when logged in', function (done) {
|
||||
// done();
|
||||
// });
|
||||
|
||||
});
|
||||
});
|
@ -5,12 +5,21 @@
|
||||
// Mocking out the models to not touch the DB would turn these into unit tests, and should probably be done in future,
|
||||
// But then again testing real code, rather than mock code, might be more useful...
|
||||
|
||||
var request = require('supertest'),
|
||||
should = require('should'),
|
||||
moment = require('moment'),
|
||||
var request = require('supertest'),
|
||||
should = require('should'),
|
||||
moment = require('moment'),
|
||||
|
||||
testUtils = require('../../utils'),
|
||||
config = require('../../../server/config');
|
||||
testUtils = require('../../utils'),
|
||||
config = require('../../../server/config'),
|
||||
|
||||
ONE_HOUR_S = 60 * 60,
|
||||
ONE_YEAR_S = 365 * 24 * ONE_HOUR_S,
|
||||
cacheRules = {
|
||||
'public': 'public, max-age=0',
|
||||
'hour': 'public, max-age=' + ONE_HOUR_S,
|
||||
'year': 'public, max-age=' + ONE_YEAR_S,
|
||||
'private': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
|
||||
};
|
||||
|
||||
describe('Frontend Routing', function () {
|
||||
function doEnd(done) {
|
||||
@ -18,6 +27,12 @@ describe('Frontend Routing', function () {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
should.not.exist(res.headers['x-cache-invalidate']);
|
||||
should.not.exist(res.headers['X-CSRF-Token']);
|
||||
should.not.exist(res.headers['set-cookie']);
|
||||
should.exist(res.headers.date);
|
||||
|
||||
done();
|
||||
};
|
||||
}
|
||||
@ -38,6 +53,7 @@ describe('Frontend Routing', function () {
|
||||
it('should respond with html', function (done) {
|
||||
request.get('/')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(200)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -45,6 +61,7 @@ describe('Frontend Routing', function () {
|
||||
it('should not have as second page', function (done) {
|
||||
request.get('/page/2/')
|
||||
.expect('Location', '/')
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -54,6 +71,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect without slash', function (done) {
|
||||
request.get('/welcome-to-ghost')
|
||||
.expect('Location', '/welcome-to-ghost/')
|
||||
.expect('Cache-Control', cacheRules.year)
|
||||
.expect(301)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -61,6 +79,7 @@ describe('Frontend Routing', function () {
|
||||
it('should respond with html', function (done) {
|
||||
request.get('/welcome-to-ghost/')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(200)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -72,17 +91,17 @@ describe('Frontend Routing', function () {
|
||||
console.log('date', date);
|
||||
|
||||
request.get('/' + date + '/welcome-to-ghost/')
|
||||
.expect('Cache-Control', cacheRules.hour)
|
||||
.expect(404)
|
||||
// TODO this error message is inconsistent
|
||||
.expect(/Page Not Found/)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should 404 for unknown post', function (done) {
|
||||
request.get('/spectacular/')
|
||||
.expect('Cache-Control', cacheRules.hour)
|
||||
.expect(404)
|
||||
// TODO this error message is inconsistent
|
||||
.expect(/Post not found/)
|
||||
.expect(/Page Not Found/)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
});
|
||||
@ -91,6 +110,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect without slash', function (done) {
|
||||
request.get('/rss')
|
||||
.expect('Location', '/rss/')
|
||||
.expect('Cache-Control', cacheRules.year)
|
||||
.expect(301)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -98,14 +118,16 @@ describe('Frontend Routing', function () {
|
||||
it('should respond with xml', function (done) {
|
||||
request.get('/rss/')
|
||||
.expect('Content-Type', /xml/)
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(200)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should not have as second page', function (done) {
|
||||
request.get('/rss/2/')
|
||||
// TODO this should probably redirect straight to /rss/ ?
|
||||
// TODO this should probably redirect straight to /rss/ with 301?
|
||||
.expect('Location', '/rss/1/')
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -129,6 +151,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect without slash', function (done) {
|
||||
request.get('/page/2')
|
||||
.expect('Location', '/page/2/')
|
||||
.expect('Cache-Control', cacheRules.year)
|
||||
.expect(301)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -136,6 +159,7 @@ describe('Frontend Routing', function () {
|
||||
it('should respond with html', function (done) {
|
||||
request.get('/page/2/')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(200)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -143,6 +167,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect page 1', function (done) {
|
||||
request.get('/page/1/')
|
||||
.expect('Location', '/')
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
// TODO: This should probably be a 301?
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
@ -151,6 +176,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect to last page is page too high', function (done) {
|
||||
request.get('/page/4/')
|
||||
.expect('Location', '/page/3/')
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -158,6 +184,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect to first page is page too low', function (done) {
|
||||
request.get('/page/0/')
|
||||
.expect('Location', '/')
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -167,6 +194,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect without slash', function (done) {
|
||||
request.get('/rss/2')
|
||||
.expect('Location', '/rss/2/')
|
||||
.expect('Cache-Control', cacheRules.year)
|
||||
.expect(301)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -174,6 +202,7 @@ describe('Frontend Routing', function () {
|
||||
it('should respond with xml', function (done) {
|
||||
request.get('/rss/2/')
|
||||
.expect('Content-Type', /xml/)
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(200)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -181,6 +210,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect page 1', function (done) {
|
||||
request.get('/rss/1/')
|
||||
.expect('Location', '/rss/')
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
// TODO: This should probably be a 301?
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
@ -189,6 +219,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect to last page is page too high', function (done) {
|
||||
request.get('/rss/3/')
|
||||
.expect('Location', '/rss/2/')
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -196,6 +227,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect to first page is page too low', function (done) {
|
||||
request.get('/rss/0/')
|
||||
.expect('Location', '/rss/')
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -205,6 +237,7 @@ describe('Frontend Routing', function () {
|
||||
it('should redirect without slash', function (done) {
|
||||
request.get('/static-page-test')
|
||||
.expect('Location', '/static-page-test/')
|
||||
.expect('Cache-Control', cacheRules.year)
|
||||
.expect(301)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
@ -212,11 +245,39 @@ describe('Frontend Routing', function () {
|
||||
it('should respond with xml', function (done) {
|
||||
request.get('/static-page-test/')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Cache-Control', cacheRules['public'])
|
||||
.expect(200)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Static assets', function () {
|
||||
it('should retrieve shared assets', function (done) {
|
||||
request.get('/shared/img/usr-image.png')
|
||||
.expect('Cache-Control', cacheRules.year)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should retrieve theme assets', function (done) {
|
||||
request.get('/assets/css/screen.css')
|
||||
.expect('Cache-Control', cacheRules.hour)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should retrieve built assets', function (done) {
|
||||
request.get('/ghost/built/vendor.js')
|
||||
.expect('Cache-Control', cacheRules.year)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
// at the moment there is no image fixture to test
|
||||
// it('should retrieve image assets', function (done) {
|
||||
// request.get('/assets/css/screen.css')
|
||||
// .expect('Cache-Control', cacheRules.year)
|
||||
// .end(doEnd(done));
|
||||
// });
|
||||
});
|
||||
|
||||
// ### The rest of the tests switch to date permalinks
|
||||
|
||||
// describe('Date permalinks', function () {
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*globals describe, beforeEach, it*/
|
||||
/*globals describe, beforeEach, afterEach, it*/
|
||||
var assert = require('assert'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
when = require('when'),
|
||||
_ = require('underscore'),
|
||||
express = require('express'),
|
||||
api = require('../../server/api');
|
||||
api = require('../../server/api'),
|
||||
middleware = require('../../server/middleware').middleware;
|
||||
|
||||
describe('Middleware', function () {
|
||||
@ -33,9 +33,9 @@ describe('Middleware', function () {
|
||||
|
||||
middleware.auth(req, res, null).then(function () {
|
||||
assert(res.redirect.calledWithMatch('/ghost/signin/'));
|
||||
return done();
|
||||
return done();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
it('should redirect to signin path with redirect paramater stripped of /ghost/', function(done) {
|
||||
@ -145,22 +145,24 @@ describe('Middleware', function () {
|
||||
|
||||
beforeEach(function (done) {
|
||||
api.notifications.add({
|
||||
id: 0,
|
||||
id: 0,
|
||||
status: 'passive',
|
||||
message: 'passive-one'
|
||||
}).then(function () {
|
||||
return api.notifications.add({
|
||||
id: 1,
|
||||
status: 'passive',
|
||||
message: 'passive-one'
|
||||
}).then(function () {
|
||||
return api.notifications.add({
|
||||
id: 1,
|
||||
status: 'passive',
|
||||
message: 'passive-two'});
|
||||
}).then(function () {
|
||||
return api.notifications.add({
|
||||
id: 2,
|
||||
status: 'aggressive',
|
||||
message: 'aggressive'});
|
||||
}).then(function () {
|
||||
done();
|
||||
message: 'passive-two'
|
||||
});
|
||||
}).then(function () {
|
||||
return api.notifications.add({
|
||||
id: 2,
|
||||
status: 'aggressive',
|
||||
message: 'aggressive'
|
||||
});
|
||||
}).then(function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should clean all passive messages', function (done) {
|
||||
@ -177,7 +179,7 @@ describe('Middleware', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('disableCachedResult', function () {
|
||||
describe('cacheControl', function () {
|
||||
var res;
|
||||
|
||||
beforeEach(function () {
|
||||
@ -186,12 +188,28 @@ describe('Middleware', function () {
|
||||
};
|
||||
});
|
||||
|
||||
it('should set correct cache headers', function (done) {
|
||||
middleware.disableCachedResult(null, res, function () {
|
||||
assert(res.set.calledWith({
|
||||
'Cache-Control': 'no-cache, must-revalidate',
|
||||
'Expires': 'Sat, 26 Jul 1997 05:00:00 GMT'
|
||||
}));
|
||||
it('correctly sets the public profile headers', function (done) {
|
||||
middleware.cacheControl('public')(null, res, function (a) {
|
||||
should.not.exist(a);
|
||||
res.set.calledOnce.should.be.true;
|
||||
res.set.calledWith({'Cache-Control': 'public, max-age=0'});
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('correctly sets the private profile headers', function (done) {
|
||||
middleware.cacheControl('private')(null, res, function (a) {
|
||||
should.not.exist(a);
|
||||
res.set.calledOnce.should.be.true;
|
||||
res.set.calledWith({'Cache-Control': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'});
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('will not set headers without a profile', function (done) {
|
||||
middleware.cacheControl()(null, res, function (a) {
|
||||
should.not.exist(a);
|
||||
res.set.called.should.be.false;
|
||||
return done();
|
||||
});
|
||||
});
|
||||
@ -235,8 +253,6 @@ describe('Middleware', function () {
|
||||
});
|
||||
|
||||
describe('staticTheme', function () {
|
||||
var realExpressStatic = express.static;
|
||||
|
||||
beforeEach(function () {
|
||||
sinon.stub(middleware, 'forwardToExpressStatic').yields();
|
||||
});
|
||||
|
@ -1,17 +1,19 @@
|
||||
/*globals describe, beforeEach, afterEach, it*/
|
||||
var testUtils = require('../utils'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
when = require('when'),
|
||||
_ = require('underscore'),
|
||||
path = require('path'),
|
||||
api = require('../../server/api'),
|
||||
hbs = require('express-hbs'),
|
||||
var testUtils = require('../utils'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
when = require('when'),
|
||||
_ = require('underscore'),
|
||||
path = require('path'),
|
||||
rewire = require('rewire'),
|
||||
api = require('../../server/api'),
|
||||
hbs = require('express-hbs'),
|
||||
|
||||
|
||||
// Stuff we are testing
|
||||
handlebars = hbs.handlebars,
|
||||
helpers = require('../../server/helpers'),
|
||||
config = require('../../server/config');
|
||||
helpers = require('../../server/helpers'),
|
||||
config = require('../../server/config');
|
||||
|
||||
describe('Core Helpers', function () {
|
||||
|
||||
@ -302,9 +304,12 @@ describe('Core Helpers', function () {
|
||||
});
|
||||
|
||||
it('returns meta tag string', function (done) {
|
||||
helpers.ghost_foot.call({version: "0.9"}).then(function (rendered) {
|
||||
|
||||
helpers.assetHash = 'abc';
|
||||
|
||||
helpers.ghost_foot.call().then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<script src=".*\/shared\/vendor\/jquery\/jquery.js\?v=0.9"><\/script>/);
|
||||
rendered.string.should.match(/<script src=".*\/shared\/vendor\/jquery\/jquery.js\?v=abc"><\/script>/);
|
||||
|
||||
done();
|
||||
}).then(null, done);
|
||||
@ -325,9 +330,9 @@ describe('Core Helpers', function () {
|
||||
|
||||
it('should output an absolute URL if the option is present', function () {
|
||||
helpers.url.call(
|
||||
{html: 'content', markdown: "ff", title: "title", slug: "slug", created_at: new Date(0)},
|
||||
{hash: { absolute: 'true'}})
|
||||
.then(function (rendered) {
|
||||
{html: 'content', markdown: "ff", title: "title", slug: "slug", created_at: new Date(0)},
|
||||
{hash: { absolute: 'true'}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.should.equal('http://testurl.com/slug/');
|
||||
});
|
||||
@ -551,13 +556,13 @@ describe('Core Helpers', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe("meta_description helper", function (done) {
|
||||
describe("meta_description helper", function () {
|
||||
|
||||
it('has loaded meta_description helper', function () {
|
||||
should.exist(handlebars.helpers.meta_description);
|
||||
});
|
||||
|
||||
it('can return blog description', function () {
|
||||
it('can return blog description', function (done) {
|
||||
helpers.meta_description.call({ghostRoot: '/'}).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('Just a blogging platform.');
|
||||
@ -578,4 +583,175 @@ describe('Core Helpers', function () {
|
||||
|
||||
});
|
||||
|
||||
describe("asset helper", function () {
|
||||
var rendered,
|
||||
configStub;
|
||||
|
||||
beforeEach(function () {
|
||||
// set the asset hash
|
||||
helpers.assetHash = 'abc';
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
if (configStub) {
|
||||
configStub.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('has loaded asset helper', function () {
|
||||
should.exist(handlebars.helpers.asset);
|
||||
});
|
||||
|
||||
it("handles favicon correctly", function () {
|
||||
// with ghost set
|
||||
rendered = helpers.asset('favicon.ico', {"hash": {ghost: 'true'}});
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/favicon.ico');
|
||||
|
||||
// without ghost set
|
||||
rendered = helpers.asset('favicon.ico');
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/favicon.ico');
|
||||
|
||||
configStub = sinon.stub(config, 'paths', function () {
|
||||
return {'subdir': '/blog'};
|
||||
});
|
||||
|
||||
// with subdirectory
|
||||
rendered = helpers.asset('favicon.ico', {"hash": {ghost: 'true'}});
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/blog/favicon.ico');
|
||||
|
||||
// without ghost set
|
||||
rendered = helpers.asset('favicon.ico');
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/blog/favicon.ico');
|
||||
});
|
||||
|
||||
it('handles shared assets correctly', function () {
|
||||
// with ghost set
|
||||
rendered = helpers.asset('shared/asset.js', {"hash": {ghost: 'true'}});
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/shared/asset.js?v=abc');
|
||||
|
||||
// without ghost set
|
||||
rendered = helpers.asset('shared/asset.js');
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/shared/asset.js?v=abc');
|
||||
|
||||
configStub = sinon.stub(config, 'paths', function () {
|
||||
return {'subdir': '/blog'};
|
||||
});
|
||||
|
||||
// with subdirectory
|
||||
rendered = helpers.asset('shared/asset.js', {"hash": {ghost: 'true'}});
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/blog/shared/asset.js?v=abc');
|
||||
|
||||
// without ghost set
|
||||
rendered = helpers.asset('shared/asset.js');
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/blog/shared/asset.js?v=abc');
|
||||
});
|
||||
|
||||
it('handles admin assets correctly', function () {
|
||||
// with ghost set
|
||||
rendered = helpers.asset('js/asset.js', {"hash": {ghost: 'true'}});
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/ghost/js/asset.js?v=abc');
|
||||
|
||||
configStub = sinon.stub(config, 'paths', function () {
|
||||
return {'subdir': '/blog'};
|
||||
});
|
||||
|
||||
// with subdirectory
|
||||
rendered = helpers.asset('js/asset.js', {"hash": {ghost: 'true'}});
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/blog/ghost/js/asset.js?v=abc');
|
||||
});
|
||||
|
||||
it('handles theme assets correctly', function () {
|
||||
// with ghost set
|
||||
rendered = helpers.asset('js/asset.js');
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/assets/js/asset.js?v=abc');
|
||||
|
||||
configStub = sinon.stub(config, 'paths', function () {
|
||||
return {'subdir': '/blog'};
|
||||
});
|
||||
|
||||
// with subdirectory
|
||||
rendered = helpers.asset('js/asset.js');
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('/blog/assets/js/asset.js?v=abc');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("ghostScriptTags helper", function () {
|
||||
var rendered,
|
||||
configStub;
|
||||
|
||||
beforeEach(function () {
|
||||
// set the asset hash
|
||||
helpers = rewire('../../server/helpers');
|
||||
helpers.assetHash = 'abc';
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
if (configStub) {
|
||||
configStub.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('has loaded ghostScriptTags helper', function () {
|
||||
should.exist(helpers.ghostScriptTags);
|
||||
});
|
||||
|
||||
it('outputs correct scripts for development mode', function () {
|
||||
rendered = helpers.ghostScriptTags();
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal(
|
||||
'<script src="/ghost/scripts/vendor.js?v=abc"></script>' +
|
||||
'<script src="/ghost/scripts/helpers.js?v=abc"></script>' +
|
||||
'<script src="/ghost/scripts/templates.js?v=abc"></script>' +
|
||||
'<script src="/ghost/scripts/models.js?v=abc"></script>' +
|
||||
'<script src="/ghost/scripts/views.js?v=abc"></script>'
|
||||
);
|
||||
|
||||
configStub = sinon.stub(config, 'paths', function () {
|
||||
return {'subdir': '/blog'};
|
||||
});
|
||||
|
||||
// with subdirectory
|
||||
rendered = helpers.ghostScriptTags();
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal(
|
||||
'<script src="/blog/ghost/scripts/vendor.js?v=abc"></script>' +
|
||||
'<script src="/blog/ghost/scripts/helpers.js?v=abc"></script>' +
|
||||
'<script src="/blog/ghost/scripts/templates.js?v=abc"></script>' +
|
||||
'<script src="/blog/ghost/scripts/models.js?v=abc"></script>' +
|
||||
'<script src="/blog/ghost/scripts/views.js?v=abc"></script>'
|
||||
);
|
||||
});
|
||||
|
||||
it('outputs correct scripts for production mode', function () {
|
||||
|
||||
helpers.__set__('isProduction', true);
|
||||
|
||||
rendered = helpers.ghostScriptTags();
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('<script src="/ghost/scripts/ghost.min.js?v=abc"></script>');
|
||||
|
||||
configStub = sinon.stub(config, 'paths', function () {
|
||||
return {'subdir': '/blog'};
|
||||
});
|
||||
|
||||
// with subdirectory
|
||||
rendered = helpers.ghostScriptTags();
|
||||
should.exist(rendered);
|
||||
String(rendered).should.equal('<script src="/blog/ghost/scripts/ghost.min.js?v=abc"></script>');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user