mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
✨ Dynamic Routing Beta: Channels
refs #9601 - refactor architecture of routing so you can define a channel - a channel is a different way of looking at your posts (a view) - a channel does not change the url of a resource Example channel ``` routes: /worldcup-2018-russia/: controller: channel filter: tag:football18 data: tag.football18 ``` - added ability to redirect resources to a channel/static route - support templates for channels - ensure we still support static routes (e.g. /about/: home) - ensure pagination + rss works out of the box
This commit is contained in:
parent
0229ac9e82
commit
c2fa469c4d
@ -1,6 +1,9 @@
|
||||
const debug = require('ghost-ignition').debug('services:routing:static-pages-router');
|
||||
const common = require('../../lib/common');
|
||||
const helpers = require('./helpers');
|
||||
const urlService = require('../../services/url');
|
||||
const RSSRouter = require('./RSSRouter');
|
||||
const controllers = require('./controllers');
|
||||
const middlewares = require('./middlewares');
|
||||
const ParentRouter = require('./ParentRouter');
|
||||
|
||||
class StaticRoutesRouter extends ParentRouter {
|
||||
@ -8,39 +11,88 @@ class StaticRoutesRouter extends ParentRouter {
|
||||
super('StaticRoutesRouter');
|
||||
|
||||
this.route = {value: mainRoute};
|
||||
this.templates = object.templates || [];
|
||||
|
||||
this.templates = (object.templates || []).reverse();
|
||||
this.data = object.data || {query: {}, router: {}};
|
||||
debug(this.route.value, this.templates);
|
||||
|
||||
this._registerRoutes();
|
||||
if (this.isChannel(object)) {
|
||||
this.filter = object.filter;
|
||||
this.limit = object.limit;
|
||||
this.order = object.order;
|
||||
|
||||
this.routerName = mainRoute === '/' ? 'index' : mainRoute.replace(/\//g, '');
|
||||
this.controller = object.controller;
|
||||
|
||||
debug(this.route.value, this.templates, this.filter, this.data);
|
||||
this._registerChannelRoutes();
|
||||
} else {
|
||||
debug(this.route.value, this.templates);
|
||||
this._registerStaticRoute();
|
||||
}
|
||||
}
|
||||
|
||||
_registerRoutes() {
|
||||
this.router().use(this._prepareContext.bind(this));
|
||||
_registerChannelRoutes() {
|
||||
this.router().use(this._prepareChannelContext.bind(this));
|
||||
|
||||
this.mountRoute(this.route.value, this._renderStaticRoute.bind(this));
|
||||
// REGISTER: enable rss by default
|
||||
this.rssRouter = new RSSRouter();
|
||||
this.mountRouter(this.route.value, this.rssRouter.router());
|
||||
|
||||
// REGISTER: channel route
|
||||
this.mountRoute(this.route.value, controllers[this.controller]);
|
||||
|
||||
// REGISTER: pagination
|
||||
this.router().param('page', middlewares.pageParam);
|
||||
this.mountRoute(urlService.utils.urlJoin(this.route.value, 'page', ':page(\\d+)'), controllers[this.controller]);
|
||||
|
||||
common.events.emit('router.created', this);
|
||||
}
|
||||
|
||||
_prepareContext(req, res, next) {
|
||||
// @TODO: index.hbs as fallback for static routes O_O
|
||||
res._route = {
|
||||
type: 'custom',
|
||||
templates: this.templates,
|
||||
defaultTemplate: 'index'
|
||||
_prepareChannelContext(req, res, next) {
|
||||
res.locals.routerOptions = {
|
||||
name: this.routerName,
|
||||
context: [this.routerName],
|
||||
filter: this.filter,
|
||||
limit: this.limit,
|
||||
order: this.order,
|
||||
data: this.data.query,
|
||||
templates: this.templates
|
||||
};
|
||||
|
||||
res.locals.routerOptions = {
|
||||
context: []
|
||||
res._route = {
|
||||
type: this.controller
|
||||
};
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
_renderStaticRoute(req, res) {
|
||||
debug('StaticRoutesRouter');
|
||||
helpers.renderer(req, res, {});
|
||||
_registerStaticRoute() {
|
||||
this.router().use(this._prepareStaticRouteContext.bind(this));
|
||||
this.mountRoute(this.route.value, controllers.static);
|
||||
|
||||
common.events.emit('router.created', this);
|
||||
}
|
||||
|
||||
_prepareStaticRouteContext(req, res, next) {
|
||||
res.locals.routerOptions = {
|
||||
data: this.data.query,
|
||||
context: []
|
||||
};
|
||||
|
||||
res._route = {
|
||||
type: 'custom',
|
||||
templates: this.templates
|
||||
};
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
isChannel(object) {
|
||||
if (object && object.controller && object.controller === 'channel') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.controller === 'channel';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
const debug = require('ghost-ignition').debug('services:routing:taxonomy-router');
|
||||
const _ = require('lodash');
|
||||
const common = require('../../lib/common');
|
||||
const ParentRouter = require('./ParentRouter');
|
||||
const RSSRouter = require('./RSSRouter');
|
||||
@ -30,15 +31,18 @@ class TaxonomyRouter extends ParentRouter {
|
||||
// REGISTER: context middleware
|
||||
this.router().use(this._prepareContext.bind(this));
|
||||
|
||||
this.router().param('slug', this._respectDominantRouter.bind(this));
|
||||
|
||||
// REGISTER: enable rss by default
|
||||
this.mountRouter(this.permalinks.getValue(), new RSSRouter().router());
|
||||
this.rssRouter = new RSSRouter();
|
||||
this.mountRouter(this.permalinks.getValue(), this.rssRouter.router());
|
||||
|
||||
// REGISTER: e.g. /tag/:slug/
|
||||
this.mountRoute(this.permalinks.getValue(), controllers.collection);
|
||||
this.mountRoute(this.permalinks.getValue(), controllers.channel);
|
||||
|
||||
// REGISTER: enable pagination for each taxonomy by default
|
||||
this.router().param('page', middlewares.pageParam);
|
||||
this.mountRoute(urlService.utils.urlJoin(this.permalinks.value, 'page', ':page(\\d+)'), controllers.collection);
|
||||
this.mountRoute(urlService.utils.urlJoin(this.permalinks.value, 'page', ':page(\\d+)'), controllers.channel);
|
||||
|
||||
this.mountRoute(urlService.utils.urlJoin(this.permalinks.value, 'edit'), this._redirectEditOption.bind(this));
|
||||
|
||||
@ -58,7 +62,7 @@ class TaxonomyRouter extends ParentRouter {
|
||||
};
|
||||
|
||||
res._route = {
|
||||
type: 'collection'
|
||||
type: 'channel'
|
||||
};
|
||||
|
||||
next();
|
||||
|
68
core/server/services/routing/controllers/channel.js
Normal file
68
core/server/services/routing/controllers/channel.js
Normal file
@ -0,0 +1,68 @@
|
||||
const _ = require('lodash'),
|
||||
debug = require('ghost-ignition').debug('services:routing:controllers:channel'),
|
||||
common = require('../../../lib/common'),
|
||||
security = require('../../../lib/security'),
|
||||
themes = require('../../themes'),
|
||||
filters = require('../../../filters'),
|
||||
helpers = require('../helpers');
|
||||
|
||||
// @TODO: the collection+rss controller does almost the same
|
||||
module.exports = function channelController(req, res, next) {
|
||||
debug('channelController', req.params, res.locals.routerOptions);
|
||||
|
||||
const pathOptions = {
|
||||
page: req.params.page !== undefined ? req.params.page : 1,
|
||||
slug: req.params.slug ? security.string.safe(req.params.slug) : undefined
|
||||
};
|
||||
|
||||
if (pathOptions.page) {
|
||||
// CASE 1: routes.yaml `limit` is stronger than theme definition
|
||||
// CASE 2: use `posts_per_page` config from theme as `limit` value
|
||||
if (res.locals.routerOptions.limit) {
|
||||
themes.getActive().updateTemplateOptions({
|
||||
data: {
|
||||
config: {
|
||||
posts_per_page: res.locals.routerOptions.limit
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pathOptions.limit = res.locals.routerOptions.limit;
|
||||
} else {
|
||||
const postsPerPage = parseInt(themes.getActive().config('posts_per_page'));
|
||||
|
||||
if (!isNaN(postsPerPage) && postsPerPage > 0) {
|
||||
pathOptions.limit = postsPerPage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return helpers.fetchData(pathOptions, res.locals.routerOptions)
|
||||
.then(function handleResult(result) {
|
||||
// CASE: requested page is greater than number of pages we have
|
||||
if (pathOptions.page > result.meta.pagination.pages) {
|
||||
return next(new common.errors.NotFoundError({
|
||||
message: common.i18n.t('errors.errors.pageNotFound')
|
||||
}));
|
||||
}
|
||||
|
||||
// Format data 1
|
||||
// @TODO: figure out if this can be removed, it's supposed to ensure that absolutely URLs get generated
|
||||
// correctly for the various objects, but I believe it doesn't work and a different approach is needed.
|
||||
helpers.secure(req, result.posts);
|
||||
|
||||
// @TODO: get rid of this O_O
|
||||
_.each(result.data, function (data) {
|
||||
helpers.secure(req, data);
|
||||
});
|
||||
|
||||
// @TODO: properly design these filters
|
||||
filters.doFilter('prePostsRender', result.posts, res.locals)
|
||||
.then(function (posts) {
|
||||
result.posts = posts;
|
||||
return result;
|
||||
})
|
||||
.then(helpers.renderEntries(req, res));
|
||||
})
|
||||
.catch(helpers.handleError(next));
|
||||
};
|
@ -2,6 +2,7 @@ const _ = require('lodash'),
|
||||
debug = require('ghost-ignition').debug('services:routing:controllers:collection'),
|
||||
common = require('../../../lib/common'),
|
||||
security = require('../../../lib/security'),
|
||||
urlService = require('../../../services/url'),
|
||||
themes = require('../../themes'),
|
||||
filters = require('../../../filters'),
|
||||
helpers = require('../helpers');
|
||||
@ -45,6 +46,13 @@ module.exports = function collectionController(req, res, next) {
|
||||
}));
|
||||
}
|
||||
|
||||
// CASE: does this post belong to this collection?
|
||||
result.posts = _.filter(result.posts, (post) => {
|
||||
if (urlService.owns(res.locals.routerOptions.identifier, post.url)) {
|
||||
return post;
|
||||
}
|
||||
});
|
||||
|
||||
// Format data 1
|
||||
// @TODO: figure out if this can be removed, it's supposed to ensure that absolutely URLs get generated
|
||||
// correctly for the various objects, but I believe it doesn't work and a different approach is needed.
|
||||
@ -61,7 +69,7 @@ module.exports = function collectionController(req, res, next) {
|
||||
result.posts = posts;
|
||||
return result;
|
||||
})
|
||||
.then(helpers.renderCollection(req, res));
|
||||
.then(helpers.renderEntries(req, res));
|
||||
})
|
||||
.catch(helpers.handleError(next));
|
||||
};
|
||||
|
@ -13,5 +13,13 @@ module.exports = {
|
||||
|
||||
get preview() {
|
||||
return require('./preview');
|
||||
},
|
||||
|
||||
get channel() {
|
||||
return require('./channel');
|
||||
},
|
||||
|
||||
get static() {
|
||||
return require('./static');
|
||||
}
|
||||
};
|
||||
|
47
core/server/services/routing/controllers/static.js
Normal file
47
core/server/services/routing/controllers/static.js
Normal file
@ -0,0 +1,47 @@
|
||||
const _ = require('lodash'),
|
||||
Promise = require('bluebird'),
|
||||
debug = require('ghost-ignition').debug('services:routing:controllers:static'),
|
||||
api = require('../../../api'),
|
||||
helpers = require('../helpers');
|
||||
|
||||
function processQuery(query) {
|
||||
query = _.cloneDeep(query);
|
||||
|
||||
// Return a promise for the api query
|
||||
return api[query.resource][query.type](query.options);
|
||||
}
|
||||
|
||||
module.exports = function staticController(req, res, next) {
|
||||
debug('staticController', res.locals.routerOptions);
|
||||
|
||||
let props = {};
|
||||
|
||||
_.each(res.locals.routerOptions.data, function (query, name) {
|
||||
props[name] = processQuery(query);
|
||||
});
|
||||
|
||||
return Promise.props(props)
|
||||
.then(function handleResult(result) {
|
||||
let response = {};
|
||||
|
||||
if (res.locals.routerOptions.data) {
|
||||
response.data = {};
|
||||
|
||||
_.each(res.locals.routerOptions.data, function (config, name) {
|
||||
if (config.type === 'browse') {
|
||||
response.data[name] = result[name];
|
||||
} else {
|
||||
response.data[name] = result[name][config.resource];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// @TODO: get rid of this O_O
|
||||
_.each(response.data, function (data) {
|
||||
helpers.secure(req, data);
|
||||
});
|
||||
|
||||
helpers.renderer(req, res, helpers.formatResponse.entries(response));
|
||||
})
|
||||
.catch(helpers.handleError(next));
|
||||
};
|
@ -4,7 +4,6 @@
|
||||
*/
|
||||
const _ = require('lodash'),
|
||||
Promise = require('bluebird'),
|
||||
urlService = require('../../url'),
|
||||
api = require('../../../api'),
|
||||
defaultPostQuery = {};
|
||||
|
||||
@ -80,7 +79,7 @@ function fetchData(pathOptions, routerOptions) {
|
||||
postQuery.options.limit = pathOptions.limit;
|
||||
}
|
||||
|
||||
// CASE: always fetch post collection
|
||||
// CASE: always fetch post entries
|
||||
// The filter can in theory contain a "%s" e.g. filter="primary_tag:%s"
|
||||
props.posts = processQuery(postQuery, pathOptions.slug);
|
||||
|
||||
@ -92,27 +91,15 @@ function fetchData(pathOptions, routerOptions) {
|
||||
return Promise.props(props)
|
||||
.then(function formatResponse(results) {
|
||||
const response = _.cloneDeep(results.posts);
|
||||
delete results.posts;
|
||||
|
||||
// CASE: does this post belong to this collection?
|
||||
// EXCEPTION: Taxonomies always list the posts which belong to a tag/author.
|
||||
if (!routerOptions.data && routerOptions.identifier) {
|
||||
response.posts = _.filter(response.posts, (post) => {
|
||||
if (urlService.owns(routerOptions.identifier, post.url)) {
|
||||
return post;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// process any remaining data
|
||||
if (!_.isEmpty(results)) {
|
||||
if (routerOptions.data) {
|
||||
response.data = {};
|
||||
|
||||
_.each(results, function (result, name) {
|
||||
if (routerOptions.data[name].type === 'browse') {
|
||||
response.data[name] = result;
|
||||
_.each(routerOptions.data, function (config, name) {
|
||||
if (config.type === 'browse') {
|
||||
response.data[name] = results[name];
|
||||
} else {
|
||||
response.data[name] = result[routerOptions.data[name].resource];
|
||||
response.data[name] = results[name][config.resource];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -6,10 +6,15 @@ const _ = require('lodash');
|
||||
* @return {Object} containing page variables
|
||||
*/
|
||||
function formatPageResponse(result) {
|
||||
var response = {
|
||||
posts: result.posts,
|
||||
pagination: result.meta.pagination
|
||||
};
|
||||
var response = {};
|
||||
|
||||
if (result.posts) {
|
||||
response.posts = result.posts;
|
||||
}
|
||||
|
||||
if (result.meta && result.meta.pagination) {
|
||||
response.pagination = result.meta.pagination;
|
||||
}
|
||||
|
||||
_.each(result.data, function (data, name) {
|
||||
if (data.meta) {
|
||||
@ -37,6 +42,6 @@ function formatResponse(post) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
collection: formatPageResponse,
|
||||
entries: formatPageResponse,
|
||||
entry: formatResponse
|
||||
};
|
||||
|
@ -7,8 +7,8 @@ module.exports = {
|
||||
return require('./fetch-data');
|
||||
},
|
||||
|
||||
get renderCollection() {
|
||||
return require('./render-collection');
|
||||
get renderEntries() {
|
||||
return require('./render-entries');
|
||||
},
|
||||
|
||||
get formatResponse() {
|
||||
|
@ -1,12 +0,0 @@
|
||||
const debug = require('ghost-ignition').debug('services:routing:helpers:render-collection'),
|
||||
formatResponse = require('./format-response'),
|
||||
renderer = require('./renderer');
|
||||
|
||||
module.exports = function renderCollection(req, res) {
|
||||
debug('renderCollection called');
|
||||
return function renderCollection(result) {
|
||||
// Format data 2
|
||||
// Render
|
||||
return renderer(req, res, formatResponse.collection(result));
|
||||
};
|
||||
};
|
12
core/server/services/routing/helpers/render-entries.js
Normal file
12
core/server/services/routing/helpers/render-entries.js
Normal file
@ -0,0 +1,12 @@
|
||||
const debug = require('ghost-ignition').debug('services:routing:helpers:render-entries'),
|
||||
formatResponse = require('./format-response'),
|
||||
renderer = require('./renderer');
|
||||
|
||||
module.exports = function renderEntries(req, res) {
|
||||
debug('renderEntries called');
|
||||
return function renderEntries(result) {
|
||||
// Format data 2
|
||||
// Render
|
||||
return renderer(req, res, formatResponse.entries(result));
|
||||
};
|
||||
};
|
@ -34,7 +34,7 @@ _private.getErrorTemplateHierarchy = function getErrorTemplateHierarchy(statusCo
|
||||
};
|
||||
|
||||
/**
|
||||
* ## Get Collection Template Hierarchy
|
||||
* ## Get Template Hierarchy
|
||||
*
|
||||
* Fetch the ordered list of templates that can be used to render this request.
|
||||
* 'index' is the default / fallback
|
||||
@ -45,7 +45,7 @@ _private.getErrorTemplateHierarchy = function getErrorTemplateHierarchy(statusCo
|
||||
* @param {Object} routerOptions
|
||||
* @returns {String[]}
|
||||
*/
|
||||
_private.getCollectionTemplateHierarchy = function getCollectionTemplateHierarchy(routerOptions, requestOptions) {
|
||||
_private.getEntriesTemplateHierarchy = function getEntriesTemplateHierarchy(routerOptions, requestOptions) {
|
||||
const templateList = ['index'];
|
||||
|
||||
// CASE: author, tag, custom collection name
|
||||
@ -57,7 +57,7 @@ _private.getCollectionTemplateHierarchy = function getCollectionTemplateHierarch
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: collections can define a template list
|
||||
// CASE: collections/channels can define a template list
|
||||
if (routerOptions.templates && routerOptions.templates.length) {
|
||||
routerOptions.templates.forEach((template) => {
|
||||
templateList.unshift(template);
|
||||
@ -145,8 +145,8 @@ _private.getTemplateForEntry = function getTemplateForEntry(postObject) {
|
||||
return _private.pickTemplate(templateList, fallback);
|
||||
};
|
||||
|
||||
_private.getTemplateForCollection = function getTemplateForCollection(routerOptions, requestOptions) {
|
||||
const templateList = _private.getCollectionTemplateHierarchy(routerOptions, requestOptions),
|
||||
_private.getTemplateForEntries = function getTemplateForEntries(routerOptions, requestOptions) {
|
||||
const templateList = _private.getEntriesTemplateHierarchy(routerOptions, requestOptions),
|
||||
fallback = templateList[templateList.length - 1];
|
||||
return _private.pickTemplate(templateList, fallback);
|
||||
};
|
||||
@ -169,21 +169,17 @@ module.exports.setTemplate = function setTemplate(req, res, data) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (routeConfig.type) {
|
||||
case 'custom':
|
||||
res._template = _private.pickTemplate(routeConfig.templates, routeConfig.defaultTemplate);
|
||||
break;
|
||||
case 'collection':
|
||||
res._template = _private.getTemplateForCollection(res.locals.routerOptions, {
|
||||
path: url.parse(req.url).pathname,
|
||||
page: req.params.page,
|
||||
slugParam: req.params.slug
|
||||
});
|
||||
break;
|
||||
case 'entry':
|
||||
res._template = _private.getTemplateForEntry(data.post);
|
||||
break;
|
||||
default:
|
||||
res._template = 'index';
|
||||
if (['channel', 'collection'].indexOf(routeConfig.type) !== -1) {
|
||||
res._template = _private.getTemplateForEntries(res.locals.routerOptions, {
|
||||
path: url.parse(req.url).pathname,
|
||||
page: req.params.page,
|
||||
slugParam: req.params.slug
|
||||
});
|
||||
} else if (routeConfig.type === 'custom') {
|
||||
res._template = _private.pickTemplate(routeConfig.templates, routeConfig.defaultTemplate);
|
||||
} else if (routeConfig.type === 'entry') {
|
||||
res._template = _private.getTemplateForEntry(data.post);
|
||||
} else {
|
||||
res._template = 'index';
|
||||
}
|
||||
};
|
||||
|
@ -1,10 +1,12 @@
|
||||
const should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
_ = require('lodash'),
|
||||
cheerio = require('cheerio'),
|
||||
testUtils = require('../../utils'),
|
||||
configUtils = require('../../utils/configUtils'),
|
||||
api = require('../../../server/api'),
|
||||
settingsService = require('../../../server/services/settings'),
|
||||
RESOURCE_CONFIG = require('../../../server/services/routing/assets/resource-config'),
|
||||
themeConfig = require('../../../server/services/themes/config'),
|
||||
siteApp = require('../../../server/web/parent-app'),
|
||||
sandbox = sinon.sandbox.create();
|
||||
@ -12,6 +14,7 @@ const should = require('should'),
|
||||
describe('Integration - Web - Site', function () {
|
||||
let app;
|
||||
|
||||
before(testUtils.teardown);
|
||||
before(testUtils.setup('users:roles', 'posts'));
|
||||
|
||||
describe('default routes.yaml', function () {
|
||||
@ -424,8 +427,8 @@ describe('Integration - Web - Site', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('extended routes.yaml (1): 2 collections', function () {
|
||||
describe('behaviour: default cases', function () {
|
||||
describe('extended routes.yaml: collections', function () {
|
||||
describe('2 collections', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {
|
||||
@ -605,51 +608,49 @@ describe('Integration - Web - Site', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('extended routes.yaml (2): static permalink route', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
describe('static permalink route', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
|
||||
collections: {
|
||||
'/podcast/': {
|
||||
permalink: '/featured/',
|
||||
filter: 'featured:true'
|
||||
collections: {
|
||||
'/podcast/': {
|
||||
permalink: '/featured/',
|
||||
filter: 'featured:true'
|
||||
},
|
||||
|
||||
'/': {
|
||||
permalink: '/:slug/'
|
||||
}
|
||||
},
|
||||
|
||||
'/': {
|
||||
permalink: '/:slug/'
|
||||
}
|
||||
},
|
||||
taxonomies: {}
|
||||
});
|
||||
|
||||
taxonomies: {}
|
||||
testUtils.integrationTesting.urlService.resetGenerators();
|
||||
testUtils.integrationTesting.defaultMocks(sandbox);
|
||||
|
||||
return testUtils.integrationTesting.initGhost()
|
||||
.then(function () {
|
||||
app = siteApp();
|
||||
|
||||
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.integrationTesting.urlService.resetGenerators();
|
||||
testUtils.integrationTesting.defaultMocks(sandbox);
|
||||
beforeEach(function () {
|
||||
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||
});
|
||||
|
||||
return testUtils.integrationTesting.initGhost()
|
||||
.then(function () {
|
||||
app = siteApp();
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||
});
|
||||
});
|
||||
after(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('behaviour: default cases', function () {
|
||||
it('serve post', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
@ -711,10 +712,323 @@ describe('Integration - Web - Site', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('primary author permalink', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
|
||||
collections: {
|
||||
'/something/': {
|
||||
permalink: '/:primary_author/:slug/'
|
||||
}
|
||||
},
|
||||
|
||||
taxonomies: {}
|
||||
});
|
||||
|
||||
testUtils.integrationTesting.urlService.resetGenerators();
|
||||
testUtils.integrationTesting.defaultMocks(sandbox);
|
||||
|
||||
return testUtils.integrationTesting.initGhost()
|
||||
.then(function () {
|
||||
app = siteApp();
|
||||
|
||||
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('serve post', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/joe-bloggs/html-ipsum/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('post');
|
||||
});
|
||||
});
|
||||
|
||||
it('post without author', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/html-ipsum/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(404);
|
||||
response.template.should.eql('error-404');
|
||||
});
|
||||
});
|
||||
|
||||
it('page', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/static-page-test/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('page');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('primary tag permalink', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
|
||||
collections: {
|
||||
'/something/': {
|
||||
permalink: '/something/:primary_tag/:slug/'
|
||||
}
|
||||
},
|
||||
|
||||
taxonomies: {}
|
||||
});
|
||||
|
||||
testUtils.integrationTesting.urlService.resetGenerators();
|
||||
testUtils.integrationTesting.defaultMocks(sandbox);
|
||||
|
||||
return testUtils.integrationTesting.initGhost()
|
||||
.then(function () {
|
||||
app = siteApp();
|
||||
|
||||
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('serve post', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/something/kitchen-sink/html-ipsum/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('post');
|
||||
});
|
||||
});
|
||||
|
||||
it('post without tag', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/something/html-ipsum/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(404);
|
||||
response.template.should.eql('error-404');
|
||||
});
|
||||
});
|
||||
|
||||
it('post without tag', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/html-ipsum/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(404);
|
||||
response.template.should.eql('error-404');
|
||||
});
|
||||
});
|
||||
|
||||
it('page', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/static-page-test/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('page');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('collection with data key', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
|
||||
collections: {
|
||||
'/food/': {
|
||||
permalink: '/food/:slug/',
|
||||
filter: 'tag:bacon',
|
||||
data: {
|
||||
query: {
|
||||
tag: {
|
||||
resource: 'tags',
|
||||
type: 'read',
|
||||
options: {
|
||||
slug: 'bacon'
|
||||
}
|
||||
}
|
||||
},
|
||||
router: {
|
||||
tags: [{redirect: true, slug: 'bacon'}]
|
||||
}
|
||||
}
|
||||
},
|
||||
'/sport/': {
|
||||
permalink: '/sport/:slug/',
|
||||
filter: 'tag:pollo',
|
||||
data: {
|
||||
query: {
|
||||
apollo: {
|
||||
resource: 'tags',
|
||||
type: 'read',
|
||||
options: {
|
||||
slug: 'pollo'
|
||||
}
|
||||
}
|
||||
},
|
||||
router: {
|
||||
tags: [{redirect: false, slug: 'bacon'}]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
taxonomies: {
|
||||
tag: '/categories/:slug/',
|
||||
author: '/authors/:slug/'
|
||||
}
|
||||
});
|
||||
|
||||
testUtils.integrationTesting.urlService.resetGenerators();
|
||||
testUtils.integrationTesting.defaultMocks(sandbox);
|
||||
|
||||
return testUtils.integrationTesting.initGhost()
|
||||
.then(function () {
|
||||
app = siteApp();
|
||||
|
||||
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('serve /food/', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/food/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('index');
|
||||
});
|
||||
});
|
||||
|
||||
it('serve bacon tag', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/categories/bacon/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(301);
|
||||
});
|
||||
});
|
||||
|
||||
it('serve /sport/', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/sport/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('index');
|
||||
});
|
||||
});
|
||||
|
||||
it('serve pollo tag', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/categories/pollo/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('extended routes.yaml (3): templates', function () {
|
||||
describe('(3) (1)', function () {
|
||||
describe('extended routes.yaml: templates', function () {
|
||||
describe('default template, no template', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
@ -784,7 +1098,7 @@ describe('Integration - Web - Site', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('(3) (2)', function () {
|
||||
describe('two templates', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
@ -836,7 +1150,7 @@ describe('Integration - Web - Site', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('(3) (3)', function () {
|
||||
describe('home.hbs priority', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
@ -908,186 +1222,278 @@ describe('Integration - Web - Site', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('extended routes.yaml (4): primary author permalink', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
describe('extended routes.yaml: routes', function () {
|
||||
describe('channels', function () {
|
||||
before(testUtils.teardown);
|
||||
before(testUtils.setup('users:roles', 'posts'));
|
||||
|
||||
collections: {
|
||||
'/something/': {
|
||||
permalink: '/:primary_author/:slug/'
|
||||
before(function () {
|
||||
testUtils.integrationTesting.defaultMocks(sandbox, {theme: 'test-theme-channels'});
|
||||
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {
|
||||
'/channel1/': {
|
||||
controller: 'channel',
|
||||
filter: 'tag:kitchen-sink',
|
||||
data: {
|
||||
query: {
|
||||
tag: {
|
||||
resource: 'tags',
|
||||
type: 'read',
|
||||
options: {
|
||||
slug: 'kitchen-sink'
|
||||
}
|
||||
}
|
||||
},
|
||||
router: {
|
||||
tags: [{redirect: true, slug: 'kitchen-sink'}]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'/channel2/': {
|
||||
controller: 'channel',
|
||||
filter: 'tag:bacon',
|
||||
data: {
|
||||
query: {
|
||||
tag: {
|
||||
resource: 'tags',
|
||||
type: 'read',
|
||||
options: {
|
||||
slug: 'bacon'
|
||||
}
|
||||
}
|
||||
},
|
||||
router: {
|
||||
tags: [{redirect: true, slug: 'bacon'}]
|
||||
}
|
||||
},
|
||||
templates: ['default']
|
||||
},
|
||||
|
||||
'/channel3/': {
|
||||
controller: 'channel',
|
||||
filter: 'author:joe-bloggs',
|
||||
data: {
|
||||
query: {
|
||||
tag: {
|
||||
resource: 'users',
|
||||
type: 'read',
|
||||
options: {
|
||||
slug: 'joe-bloggs'
|
||||
}
|
||||
}
|
||||
},
|
||||
router: {
|
||||
users: [{redirect: true, slug: 'joe-bloggs'}]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'/channel4/': {
|
||||
controller: 'channel',
|
||||
filter: 'author:joe-bloggs'
|
||||
},
|
||||
|
||||
'/channel5/': {
|
||||
controller: 'channel',
|
||||
data: {
|
||||
query: {
|
||||
tag: {
|
||||
resource: 'users',
|
||||
type: 'read',
|
||||
options: {
|
||||
slug: 'joe-bloggs'
|
||||
}
|
||||
}
|
||||
},
|
||||
router: {
|
||||
users: [{redirect: true, slug: 'joe-bloggs'}]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
collections: {},
|
||||
|
||||
taxonomies: {
|
||||
tag: '/tag/:slug/',
|
||||
author: '/author/:slug/'
|
||||
}
|
||||
},
|
||||
|
||||
taxonomies: {}
|
||||
});
|
||||
|
||||
testUtils.integrationTesting.urlService.resetGenerators();
|
||||
testUtils.integrationTesting.defaultMocks(sandbox);
|
||||
|
||||
return testUtils.integrationTesting.initGhost()
|
||||
.then(function () {
|
||||
app = siteApp();
|
||||
|
||||
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||
});
|
||||
testUtils.integrationTesting.urlService.resetGenerators();
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
return testUtils.integrationTesting.initGhost()
|
||||
.then(function () {
|
||||
app = siteApp();
|
||||
|
||||
after(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||
});
|
||||
});
|
||||
|
||||
describe('behaviour: default cases', function () {
|
||||
it('serve post', function () {
|
||||
beforeEach(function () {
|
||||
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('serve channel 1', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/joe-bloggs/html-ipsum/',
|
||||
url: '/channel1/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
const $ = cheerio.load(response.body);
|
||||
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('index');
|
||||
|
||||
$('.post-card').length.should.equal(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('serve channel 1: rss', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/channel1/rss/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('post');
|
||||
response.headers['content-type'].should.eql('text/xml; charset=UTF-8');
|
||||
});
|
||||
});
|
||||
|
||||
it('post without author', function () {
|
||||
it('serve channel 2', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/html-ipsum/',
|
||||
url: '/channel2/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(404);
|
||||
response.template.should.eql('error-404');
|
||||
const $ = cheerio.load(response.body);
|
||||
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('default');
|
||||
|
||||
// default tempalte does not list posts
|
||||
$('.post-card').length.should.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('page', function () {
|
||||
it('serve channel 3', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/static-page-test/',
|
||||
url: '/channel3/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
const $ = cheerio.load(response.body);
|
||||
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('channel3');
|
||||
});
|
||||
});
|
||||
|
||||
it('serve channel 4', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/channel4/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
const $ = cheerio.load(response.body);
|
||||
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('index');
|
||||
|
||||
$('.post-card').length.should.equal(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('serve channel 5', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/channel5/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
const $ = cheerio.load(response.body);
|
||||
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('index');
|
||||
|
||||
$('.post-card').length.should.equal(4);
|
||||
});
|
||||
});
|
||||
|
||||
it('serve kitching-sink', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/tag/kitchen-sink/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(301);
|
||||
response.headers.location.should.eql('/channel1/');
|
||||
});
|
||||
});
|
||||
|
||||
it('serve chorizo: no redirect', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/tag/chorizo/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('page');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('extended routes.yaml (4): primary tag permalink', function () {
|
||||
before(function () {
|
||||
sandbox.stub(settingsService, 'get').returns({
|
||||
routes: {},
|
||||
|
||||
collections: {
|
||||
'/something/': {
|
||||
permalink: '/something/:primary_tag/:slug/'
|
||||
}
|
||||
},
|
||||
|
||||
taxonomies: {}
|
||||
});
|
||||
|
||||
testUtils.integrationTesting.urlService.resetGenerators();
|
||||
testUtils.integrationTesting.defaultMocks(sandbox);
|
||||
|
||||
return testUtils.integrationTesting.initGhost()
|
||||
.then(function () {
|
||||
app = siteApp();
|
||||
|
||||
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
after(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('behaviour: default cases', function () {
|
||||
it('serve post', function () {
|
||||
it('serve joe-bloggs', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/something/kitchen-sink/html-ipsum/',
|
||||
url: '/author/joe-bloggs/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('post');
|
||||
});
|
||||
});
|
||||
|
||||
it('post without tag', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/something/html-ipsum/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(404);
|
||||
response.template.should.eql('error-404');
|
||||
});
|
||||
});
|
||||
|
||||
it('post without tag', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/html-ipsum/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(404);
|
||||
response.template.should.eql('error-404');
|
||||
});
|
||||
});
|
||||
|
||||
it('page', function () {
|
||||
const req = {
|
||||
secure: true,
|
||||
method: 'GET',
|
||||
url: '/static-page-test/',
|
||||
host: 'example.com'
|
||||
};
|
||||
|
||||
return testUtils.mocks.express.invoke(app, req)
|
||||
.then(function (response) {
|
||||
response.statusCode.should.eql(200);
|
||||
response.template.should.eql('page');
|
||||
response.statusCode.should.eql(301);
|
||||
response.headers.location.should.eql('/channel3/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,6 +2,7 @@ const should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
settingsCache = require('../../../../server/services/settings/cache'),
|
||||
common = require('../../../../server/lib/common'),
|
||||
controllers = require('../../../../server/services/routing/controllers'),
|
||||
StaticRoutesRouter = require('../../../../server/services/routing/StaticRoutesRouter'),
|
||||
configUtils = require('../../../utils/configUtils'),
|
||||
sandbox = sinon.sandbox.create();
|
||||
@ -50,21 +51,220 @@ describe('UNIT - services/routing/StaticRoutesRouter', function () {
|
||||
|
||||
// parent route
|
||||
staticRoutesRouter.mountRoute.args[0][0].should.eql('/about/');
|
||||
staticRoutesRouter.mountRoute.args[0][1].should.eql(staticRoutesRouter._renderStaticRoute.bind(staticRoutesRouter));
|
||||
staticRoutesRouter.mountRoute.args[0][1].should.eql(controllers.static);
|
||||
});
|
||||
|
||||
it('fn: _prepareContext', function () {
|
||||
it('initialise with data+filter', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/about/', {
|
||||
data: {query: {}, router: {}},
|
||||
filter: 'tag:test'
|
||||
});
|
||||
|
||||
should.exist(staticRoutesRouter.router);
|
||||
|
||||
should.not.exist(staticRoutesRouter.getPermalinks());
|
||||
should.not.exist(staticRoutesRouter.getFilter());
|
||||
staticRoutesRouter.templates.should.eql([]);
|
||||
|
||||
common.events.emit.calledOnce.should.be.true();
|
||||
common.events.emit.calledWith('router.created', staticRoutesRouter).should.be.true();
|
||||
|
||||
staticRoutesRouter.mountRoute.callCount.should.eql(1);
|
||||
|
||||
// parent route
|
||||
staticRoutesRouter.mountRoute.args[0][0].should.eql('/about/');
|
||||
staticRoutesRouter.mountRoute.args[0][1].should.eql(controllers.static);
|
||||
});
|
||||
|
||||
it('fn: _prepareStaticRouteContext', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/about/', {templates: []});
|
||||
|
||||
staticRoutesRouter._prepareContext(req, res, next);
|
||||
staticRoutesRouter._prepareStaticRouteContext(req, res, next);
|
||||
next.called.should.be.true();
|
||||
res._route.should.eql({
|
||||
type: 'custom',
|
||||
templates: [],
|
||||
defaultTemplate: 'index'
|
||||
templates: []
|
||||
});
|
||||
|
||||
res.locals.routerOptions.should.eql({context: []});
|
||||
res.locals.routerOptions.should.eql({context: [], data: {}});
|
||||
should.not.exist(res.locals.slug);
|
||||
});
|
||||
});
|
||||
|
||||
describe('channels', function () {
|
||||
describe('initialise', function () {
|
||||
it('initialise with controller+data+filter', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/channel/', {
|
||||
controller: 'channel',
|
||||
data: {query: {}, router: {}},
|
||||
filter: 'tag:test'
|
||||
});
|
||||
|
||||
should.exist(staticRoutesRouter.router);
|
||||
|
||||
should.not.exist(staticRoutesRouter.getPermalinks());
|
||||
staticRoutesRouter.getFilter().should.eql('tag:test');
|
||||
staticRoutesRouter.templates.should.eql([]);
|
||||
should.exist(staticRoutesRouter.data);
|
||||
|
||||
common.events.emit.calledOnce.should.be.true();
|
||||
common.events.emit.calledWith('router.created', staticRoutesRouter).should.be.true();
|
||||
|
||||
staticRoutesRouter.mountRoute.callCount.should.eql(2);
|
||||
|
||||
// parent route
|
||||
staticRoutesRouter.mountRoute.args[0][0].should.eql('/channel/');
|
||||
staticRoutesRouter.mountRoute.args[0][1].should.eql(controllers.channel);
|
||||
|
||||
// pagination feature
|
||||
staticRoutesRouter.mountRoute.args[1][0].should.eql('/channel/page/:page(\\d+)');
|
||||
staticRoutesRouter.mountRoute.args[1][1].should.eql(controllers.channel);
|
||||
});
|
||||
|
||||
it('initialise with controller+filter', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/channel/', {
|
||||
controller: 'channel',
|
||||
filter: 'tag:test'
|
||||
});
|
||||
|
||||
should.exist(staticRoutesRouter.router);
|
||||
|
||||
should.not.exist(staticRoutesRouter.getPermalinks());
|
||||
staticRoutesRouter.getFilter().should.eql('tag:test');
|
||||
|
||||
staticRoutesRouter.templates.should.eql([]);
|
||||
|
||||
common.events.emit.calledOnce.should.be.true();
|
||||
common.events.emit.calledWith('router.created', staticRoutesRouter).should.be.true();
|
||||
|
||||
staticRoutesRouter.mountRoute.callCount.should.eql(2);
|
||||
|
||||
// parent route
|
||||
staticRoutesRouter.mountRoute.args[0][0].should.eql('/channel/');
|
||||
staticRoutesRouter.mountRoute.args[0][1].should.eql(controllers.channel);
|
||||
|
||||
// pagination feature
|
||||
staticRoutesRouter.mountRoute.args[1][0].should.eql('/channel/page/:page(\\d+)');
|
||||
staticRoutesRouter.mountRoute.args[1][1].should.eql(controllers.channel);
|
||||
});
|
||||
|
||||
it('initialise with controller+data', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/channel/', {
|
||||
controller: 'channel',
|
||||
data: {query: {}, router: {}},
|
||||
});
|
||||
|
||||
should.not.exist(staticRoutesRouter.getFilter());
|
||||
});
|
||||
|
||||
it('initialise on subdirectory with controller+data+filter', function () {
|
||||
configUtils.set('url', 'http://localhost:2366/blog/');
|
||||
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/channel/', {
|
||||
controller: 'channel',
|
||||
data: {query: {}, router: {}},
|
||||
filter: 'author:michi'
|
||||
});
|
||||
|
||||
staticRoutesRouter.mountRoute.callCount.should.eql(2);
|
||||
|
||||
// parent route
|
||||
staticRoutesRouter.mountRoute.args[0][0].should.eql('/channel/');
|
||||
staticRoutesRouter.mountRoute.args[0][1].should.eql(controllers.channel);
|
||||
|
||||
// pagination feature
|
||||
staticRoutesRouter.mountRoute.args[1][0].should.eql('/channel/page/:page(\\d+)');
|
||||
staticRoutesRouter.mountRoute.args[1][1].should.eql(controllers.channel);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fn: _prepareChannelContext', function () {
|
||||
it('with data+filter', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/channel/', {
|
||||
controller: 'channel',
|
||||
data: {query: {}, router: {}},
|
||||
filter: 'tag:test'
|
||||
});
|
||||
|
||||
staticRoutesRouter._prepareChannelContext(req, res, next);
|
||||
next.calledOnce.should.eql(true);
|
||||
res.locals.routerOptions.should.eql({
|
||||
context: ['channel'],
|
||||
filter: 'tag:test',
|
||||
name: 'channel',
|
||||
data: {},
|
||||
limit: undefined,
|
||||
order: undefined,
|
||||
templates: []
|
||||
});
|
||||
|
||||
res._route.type.should.eql('channel');
|
||||
});
|
||||
|
||||
it('with data', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/nothingcomparestoyou/', {
|
||||
controller: 'channel',
|
||||
data: {query: {type: 'read'}, router: {}}
|
||||
});
|
||||
|
||||
staticRoutesRouter._prepareChannelContext(req, res, next);
|
||||
next.calledOnce.should.eql(true);
|
||||
res.locals.routerOptions.should.eql({
|
||||
context: ['nothingcomparestoyou'],
|
||||
name: 'nothingcomparestoyou',
|
||||
filter: undefined,
|
||||
data: {type: 'read'},
|
||||
limit: undefined,
|
||||
order: undefined,
|
||||
templates: []
|
||||
});
|
||||
|
||||
res._route.type.should.eql('channel');
|
||||
});
|
||||
|
||||
it('with filter', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/channel/', {
|
||||
controller: 'channel',
|
||||
filter: 'tag:test'
|
||||
});
|
||||
|
||||
staticRoutesRouter._prepareChannelContext(req, res, next);
|
||||
next.calledOnce.should.eql(true);
|
||||
res.locals.routerOptions.should.eql({
|
||||
context: ['channel'],
|
||||
filter: 'tag:test',
|
||||
name: 'channel',
|
||||
limit: undefined,
|
||||
order: undefined,
|
||||
data: {},
|
||||
templates: []
|
||||
});
|
||||
|
||||
res._route.type.should.eql('channel');
|
||||
});
|
||||
|
||||
it('with order+limit', function () {
|
||||
const staticRoutesRouter = new StaticRoutesRouter('/channel/', {
|
||||
controller: 'channel',
|
||||
filter: 'tag:test',
|
||||
limit: 2,
|
||||
order: 'published_at asc'
|
||||
});
|
||||
|
||||
staticRoutesRouter._prepareChannelContext(req, res, next);
|
||||
next.calledOnce.should.eql(true);
|
||||
res.locals.routerOptions.should.eql({
|
||||
context: ['channel'],
|
||||
filter: 'tag:test',
|
||||
name: 'channel',
|
||||
limit: 2,
|
||||
order: 'published_at asc',
|
||||
data: {},
|
||||
templates: []
|
||||
});
|
||||
|
||||
res._route.type.should.eql('channel');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
83
core/test/unit/services/routing/TaxonomyRouter_spec.js
Normal file
83
core/test/unit/services/routing/TaxonomyRouter_spec.js
Normal file
@ -0,0 +1,83 @@
|
||||
const should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
_ = require('lodash'),
|
||||
settingsCache = require('../../../../server/services/settings/cache'),
|
||||
common = require('../../../../server/lib/common'),
|
||||
controllers = require('../../../../server/services/routing/controllers'),
|
||||
TaxonomyRouter = require('../../../../server/services/routing/TaxonomyRouter'),
|
||||
RESOURCE_CONFIG = require('../../../../server/services/routing/assets/resource-config'),
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('UNIT - services/routing/TaxonomyRouter', function () {
|
||||
let req, res, next;
|
||||
|
||||
beforeEach(function () {
|
||||
sandbox.stub(settingsCache, 'get').withArgs('permalinks').returns('/:slug/');
|
||||
|
||||
sandbox.stub(common.events, 'emit');
|
||||
sandbox.stub(common.events, 'on');
|
||||
|
||||
sandbox.spy(TaxonomyRouter.prototype, 'mountRoute');
|
||||
sandbox.spy(TaxonomyRouter.prototype, 'mountRouter');
|
||||
|
||||
req = sandbox.stub();
|
||||
res = sandbox.stub();
|
||||
next = sandbox.stub();
|
||||
|
||||
res.locals = {};
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('instantiate', function () {
|
||||
const taxonomyRouter = new TaxonomyRouter('tag', '/tag/:slug/');
|
||||
|
||||
should.exist(taxonomyRouter.router);
|
||||
should.exist(taxonomyRouter.rssRouter);
|
||||
|
||||
taxonomyRouter.taxonomyKey.should.eql('tag');
|
||||
taxonomyRouter.getPermalinks().getValue().should.eql('/tag/:slug/');
|
||||
|
||||
common.events.emit.calledOnce.should.be.true();
|
||||
common.events.emit.calledWith('router.created', taxonomyRouter).should.be.true();
|
||||
|
||||
taxonomyRouter.mountRouter.callCount.should.eql(1);
|
||||
taxonomyRouter.mountRouter.args[0][0].should.eql('/tag/:slug/');
|
||||
taxonomyRouter.mountRouter.args[0][1].should.eql(taxonomyRouter.rssRouter.router());
|
||||
|
||||
taxonomyRouter.mountRoute.callCount.should.eql(3);
|
||||
|
||||
// permalink route
|
||||
taxonomyRouter.mountRoute.args[0][0].should.eql('/tag/:slug/');
|
||||
taxonomyRouter.mountRoute.args[0][1].should.eql(controllers.channel);
|
||||
|
||||
// pagination feature
|
||||
taxonomyRouter.mountRoute.args[1][0].should.eql('/tag/:slug/page/:page(\\d+)');
|
||||
taxonomyRouter.mountRoute.args[1][1].should.eql(controllers.channel);
|
||||
|
||||
// edit feature
|
||||
taxonomyRouter.mountRoute.args[2][0].should.eql('/tag/:slug/edit');
|
||||
taxonomyRouter.mountRoute.args[2][1].should.eql(taxonomyRouter._redirectEditOption.bind(taxonomyRouter));
|
||||
});
|
||||
|
||||
it('fn: _prepareContext', function () {
|
||||
const taxonomyRouter = new TaxonomyRouter('tag', '/tag/:slug/');
|
||||
taxonomyRouter._prepareContext(req, res, next);
|
||||
next.calledOnce.should.eql(true);
|
||||
|
||||
res.locals.routerOptions.should.eql({
|
||||
name: 'tag',
|
||||
permalinks: '/tag/:slug/',
|
||||
type: RESOURCE_CONFIG.QUERY.tag.resource,
|
||||
data: {tag: _.omit(RESOURCE_CONFIG.QUERY.tag, 'alias')},
|
||||
filter: RESOURCE_CONFIG.TAXONOMIES.tag.filter,
|
||||
context: ['tag'],
|
||||
slugTemplate: true,
|
||||
identifier: taxonomyRouter.identifier
|
||||
});
|
||||
|
||||
res._route.type.should.eql('channel');
|
||||
});
|
||||
});
|
264
core/test/unit/services/routing/controllers/channel_spec.js
Normal file
264
core/test/unit/services/routing/controllers/channel_spec.js
Normal file
@ -0,0 +1,264 @@
|
||||
const should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
testUtils = require('../../../../utils'),
|
||||
common = require('../../../../../server/lib/common'),
|
||||
security = require('../../../../../server/lib/security'),
|
||||
filters = require('../../../../../server/filters'),
|
||||
themeService = require('../../../../../server/services/themes'),
|
||||
controllers = require('../../../../../server/services/routing/controllers'),
|
||||
helpers = require('../../../../../server/services/routing/helpers'),
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
function failTest(done) {
|
||||
return function (err) {
|
||||
should.exist(err);
|
||||
done(err);
|
||||
};
|
||||
}
|
||||
|
||||
describe('Unit - services/routing/controllers/channel', function () {
|
||||
let req, res, fetchDataStub, secureStub, renderStub, posts, postsPerPage;
|
||||
|
||||
beforeEach(function () {
|
||||
postsPerPage = 5;
|
||||
|
||||
posts = [
|
||||
testUtils.DataGenerator.forKnex.createPost()
|
||||
];
|
||||
|
||||
secureStub = sandbox.stub();
|
||||
fetchDataStub = sandbox.stub();
|
||||
renderStub = sandbox.stub();
|
||||
|
||||
sandbox.stub(helpers, 'fetchData').get(function () {
|
||||
return fetchDataStub;
|
||||
});
|
||||
|
||||
sandbox.stub(security.string, 'safe').returns('safe');
|
||||
|
||||
sandbox.stub(helpers, 'secure').get(function () {
|
||||
return secureStub;
|
||||
});
|
||||
|
||||
sandbox.stub(themeService, 'getActive').returns({
|
||||
updateTemplateOptions: sandbox.stub(),
|
||||
config: function (key) {
|
||||
key.should.eql('posts_per_page');
|
||||
return postsPerPage;
|
||||
}
|
||||
});
|
||||
|
||||
sandbox.stub(helpers, 'renderEntries').get(function () {
|
||||
return renderStub;
|
||||
});
|
||||
|
||||
sandbox.stub(filters, 'doFilter');
|
||||
|
||||
req = {
|
||||
path: '/',
|
||||
params: {},
|
||||
route: {}
|
||||
};
|
||||
|
||||
res = {
|
||||
locals: {
|
||||
routerOptions: {}
|
||||
},
|
||||
render: sinon.spy(),
|
||||
redirect: sinon.spy()
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('no params', function (done) {
|
||||
fetchDataStub.withArgs({page: 1, slug: undefined, limit: postsPerPage}, res.locals.routerOptions)
|
||||
.resolves({
|
||||
posts: posts,
|
||||
meta: {
|
||||
pagination: {
|
||||
pages: 5
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filters.doFilter.withArgs('prePostsRender', posts, res.locals).resolves();
|
||||
|
||||
renderStub.callsFake(function () {
|
||||
themeService.getActive.calledOnce.should.be.true();
|
||||
security.string.safe.calledOnce.should.be.false();
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.channel(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('pass page param', function (done) {
|
||||
req.params.page = 2;
|
||||
|
||||
fetchDataStub.withArgs({page: 2, slug: undefined, limit: postsPerPage}, res.locals.routerOptions)
|
||||
.resolves({
|
||||
posts: posts,
|
||||
meta: {
|
||||
pagination: {
|
||||
pages: 5
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filters.doFilter.withArgs('prePostsRender', posts, res.locals).resolves();
|
||||
|
||||
renderStub.callsFake(function () {
|
||||
themeService.getActive.calledOnce.should.be.true();
|
||||
security.string.safe.calledOnce.should.be.false();
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.channel(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('update hbs engine: router defines limit', function (done) {
|
||||
res.locals.routerOptions.limit = 3;
|
||||
req.params.page = 2;
|
||||
|
||||
fetchDataStub.withArgs({page: 2, slug: undefined, limit: 3}, res.locals.routerOptions)
|
||||
.resolves({
|
||||
posts: posts,
|
||||
meta: {
|
||||
pagination: {
|
||||
pages: 3
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filters.doFilter.withArgs('prePostsRender', posts, res.locals).resolves();
|
||||
|
||||
renderStub.callsFake(function () {
|
||||
themeService.getActive.calledOnce.should.be.true();
|
||||
themeService.getActive().updateTemplateOptions.withArgs({data: {config: {posts_per_page: 3}}}).calledOnce.should.be.true();
|
||||
security.string.safe.calledOnce.should.be.false();
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.channel(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('page param too big', function (done) {
|
||||
req.params.page = 6;
|
||||
|
||||
fetchDataStub.withArgs({page: 6, slug: undefined, limit: postsPerPage}, res.locals.routerOptions)
|
||||
.resolves({
|
||||
posts: posts,
|
||||
meta: {
|
||||
pagination: {
|
||||
pages: 5
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
controllers.channel(req, res, function (err) {
|
||||
(err instanceof common.errors.NotFoundError).should.be.true();
|
||||
|
||||
themeService.getActive.calledOnce.should.be.true();
|
||||
security.string.safe.calledOnce.should.be.false();
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.false();
|
||||
renderStub.calledOnce.should.be.false();
|
||||
secureStub.calledOnce.should.be.false();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('slug param', function (done) {
|
||||
req.params.slug = 'unsafe';
|
||||
|
||||
fetchDataStub.withArgs({page: 1, slug: 'safe', limit: postsPerPage}, res.locals.routerOptions)
|
||||
.resolves({
|
||||
posts: posts,
|
||||
meta: {
|
||||
pagination: {
|
||||
pages: 5
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filters.doFilter.withArgs('prePostsRender', posts, res.locals).resolves();
|
||||
|
||||
renderStub.callsFake(function () {
|
||||
themeService.getActive.calledOnce.should.be.true();
|
||||
security.string.safe.calledOnce.should.be.true();
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.channel(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('invalid posts per page', function (done) {
|
||||
postsPerPage = -1;
|
||||
|
||||
fetchDataStub.withArgs({page: 1, slug: undefined}, res.locals.routerOptions)
|
||||
.resolves({
|
||||
posts: posts,
|
||||
meta: {
|
||||
pagination: {
|
||||
pages: 5
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filters.doFilter.withArgs('prePostsRender', posts, res.locals).resolves();
|
||||
|
||||
renderStub.callsFake(function () {
|
||||
themeService.getActive.calledOnce.should.be.true();
|
||||
security.string.safe.calledOnce.should.be.false();
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.channel(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('ensure secure helper get\'s called for data object', function (done) {
|
||||
fetchDataStub.withArgs({page: 1, slug: undefined, limit: postsPerPage}, res.locals.routerOptions)
|
||||
.resolves({
|
||||
posts: posts,
|
||||
data: {
|
||||
tag: [testUtils.DataGenerator.forKnex.createTag()]
|
||||
},
|
||||
meta: {
|
||||
pagination: {
|
||||
pages: 5
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filters.doFilter.withArgs('prePostsRender', posts, res.locals).resolves();
|
||||
|
||||
renderStub.callsFake(function () {
|
||||
themeService.getActive.calledOnce.should.be.true();
|
||||
security.string.safe.calledOnce.should.be.false();
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledTwice.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.channel(req, res, failTest(done));
|
||||
});
|
||||
});
|
@ -49,12 +49,15 @@ describe('Unit - services/routing/controllers/collection', function () {
|
||||
}
|
||||
});
|
||||
|
||||
sandbox.stub(helpers, 'renderCollection').get(function () {
|
||||
sandbox.stub(helpers, 'renderEntries').get(function () {
|
||||
return renderStub;
|
||||
});
|
||||
|
||||
sandbox.stub(filters, 'doFilter');
|
||||
|
||||
sandbox.stub(urlService, 'owns');
|
||||
urlService.owns.withArgs('identifier', posts[0].url).returns(true);
|
||||
|
||||
req = {
|
||||
path: '/',
|
||||
params: {},
|
||||
@ -63,7 +66,9 @@ describe('Unit - services/routing/controllers/collection', function () {
|
||||
|
||||
res = {
|
||||
locals: {
|
||||
routerOptions: {}
|
||||
routerOptions: {
|
||||
identifier: 'identifier'
|
||||
}
|
||||
},
|
||||
render: sinon.spy(),
|
||||
redirect: sinon.spy()
|
||||
@ -93,6 +98,7 @@ describe('Unit - services/routing/controllers/collection', function () {
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
urlService.owns.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
@ -120,6 +126,7 @@ describe('Unit - services/routing/controllers/collection', function () {
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
urlService.owns.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
@ -178,7 +185,7 @@ describe('Unit - services/routing/controllers/collection', function () {
|
||||
filters.doFilter.calledOnce.should.be.false();
|
||||
renderStub.calledOnce.should.be.false();
|
||||
secureStub.calledOnce.should.be.false();
|
||||
|
||||
urlService.owns.calledOnce.should.be.false();
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -204,6 +211,7 @@ describe('Unit - services/routing/controllers/collection', function () {
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
urlService.owns.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
@ -231,6 +239,7 @@ describe('Unit - services/routing/controllers/collection', function () {
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledOnce.should.be.true();
|
||||
urlService.owns.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
@ -259,6 +268,51 @@ describe('Unit - services/routing/controllers/collection', function () {
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledTwice.should.be.true();
|
||||
urlService.owns.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.collection(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should verify if post belongs to collection', function (done) {
|
||||
posts = [
|
||||
testUtils.DataGenerator.forKnex.createPost({url: '/a/'}),
|
||||
testUtils.DataGenerator.forKnex.createPost({url: '/b/'}),
|
||||
testUtils.DataGenerator.forKnex.createPost({url: '/c/'}),
|
||||
testUtils.DataGenerator.forKnex.createPost({url: '/d/'})
|
||||
];
|
||||
|
||||
res.locals.routerOptions.filter = 'featured:true';
|
||||
|
||||
urlService.owns.reset();
|
||||
urlService.owns.withArgs('identifier', posts[0].url).returns(false);
|
||||
urlService.owns.withArgs('identifier', posts[1].url).returns(true);
|
||||
urlService.owns.withArgs('identifier', posts[2].url).returns(false);
|
||||
urlService.owns.withArgs('identifier', posts[3].url).returns(false);
|
||||
|
||||
fetchDataStub.withArgs({page: 1, slug: undefined, limit: postsPerPage}, res.locals.routerOptions)
|
||||
.resolves({
|
||||
posts: posts,
|
||||
data: {
|
||||
tag: [testUtils.DataGenerator.forKnex.createTag()]
|
||||
},
|
||||
meta: {
|
||||
pagination: {
|
||||
pages: 5
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
filters.doFilter.withArgs('prePostsRender', [posts[1]], res.locals).resolves();
|
||||
|
||||
renderStub.callsFake(function () {
|
||||
themeService.getActive.calledOnce.should.be.true();
|
||||
security.string.safe.calledOnce.should.be.false();
|
||||
fetchDataStub.calledOnce.should.be.true();
|
||||
filters.doFilter.calledOnce.should.be.true();
|
||||
secureStub.calledTwice.should.be.true();
|
||||
urlService.owns.callCount.should.eql(4);
|
||||
done();
|
||||
});
|
||||
|
||||
|
110
core/test/unit/services/routing/controllers/static_spec.js
Normal file
110
core/test/unit/services/routing/controllers/static_spec.js
Normal file
@ -0,0 +1,110 @@
|
||||
const should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
testUtils = require('../../../../utils'),
|
||||
api = require('../../../../../server/api'),
|
||||
themeService = require('../../../../../server/services/themes'),
|
||||
helpers = require('../../../../../server/services/routing/helpers'),
|
||||
controllers = require('../../../../../server/services/routing/controllers'),
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
function failTest(done) {
|
||||
return function (err) {
|
||||
should.exist(err);
|
||||
done(err);
|
||||
};
|
||||
}
|
||||
|
||||
describe('Unit - services/routing/controllers/static', function () {
|
||||
let req, res, secureStub, renderStub, handleErrorStub, formatResponseStub, posts, postsPerPage;
|
||||
|
||||
beforeEach(function () {
|
||||
postsPerPage = 5;
|
||||
|
||||
posts = [
|
||||
testUtils.DataGenerator.forKnex.createPost()
|
||||
];
|
||||
|
||||
secureStub = sandbox.stub();
|
||||
renderStub = sandbox.stub();
|
||||
handleErrorStub = sandbox.stub();
|
||||
formatResponseStub = sandbox.stub();
|
||||
formatResponseStub.entries = sandbox.stub();
|
||||
|
||||
sandbox.stub(api.tags, 'read');
|
||||
|
||||
sandbox.stub(helpers, 'secure').get(function () {
|
||||
return secureStub;
|
||||
});
|
||||
|
||||
sandbox.stub(helpers, 'handleError').get(function () {
|
||||
return handleErrorStub;
|
||||
});
|
||||
|
||||
sandbox.stub(themeService, 'getActive').returns({
|
||||
config: function (key) {
|
||||
key.should.eql('posts_per_page');
|
||||
return postsPerPage;
|
||||
}
|
||||
});
|
||||
|
||||
sandbox.stub(helpers, 'renderer').get(function () {
|
||||
return renderStub;
|
||||
});
|
||||
|
||||
sandbox.stub(helpers, 'formatResponse').get(function () {
|
||||
return formatResponseStub;
|
||||
});
|
||||
|
||||
req = {
|
||||
path: '/',
|
||||
params: {},
|
||||
route: {}
|
||||
};
|
||||
|
||||
res = {
|
||||
locals: {
|
||||
routerOptions: {}
|
||||
},
|
||||
render: sinon.spy(),
|
||||
redirect: sinon.spy()
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('no extra data to fetch', function (done) {
|
||||
helpers.renderer.callsFake(function () {
|
||||
helpers.formatResponse.entries.withArgs({}).calledOnce.should.be.true();
|
||||
api.tags.read.called.should.be.false();
|
||||
helpers.secure.called.should.be.false();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.static(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('extra data to fetch', function (done) {
|
||||
res.locals.routerOptions.data = {
|
||||
tag: {
|
||||
resource: 'tags',
|
||||
type: 'read',
|
||||
options: {
|
||||
slug: 'bacon'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
api.tags.read.withArgs({slug: 'bacon'}).resolves({tags: [{slug: 'bacon'}]});
|
||||
|
||||
helpers.renderer.callsFake(function () {
|
||||
api.tags.read.withArgs({slug: 'bacon'}).called.should.be.true();
|
||||
helpers.formatResponse.entries.withArgs({data: {tag: [{slug: 'bacon'}]}}).calledOnce.should.be.true();
|
||||
helpers.secure.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
controllers.static(req, res, failTest(done));
|
||||
});
|
||||
});
|
@ -1,7 +1,6 @@
|
||||
const should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
api = require('../../../../../server/api'),
|
||||
urlService = require('../../../../../server/services/url'),
|
||||
helpers = require('../../../../../server/services/routing/helpers'),
|
||||
testUtils = require('../../../../utils'),
|
||||
sandbox = sinon.sandbox.create();
|
||||
@ -35,8 +34,6 @@ describe('Unit - services/routing/helpers/fetch-data', function () {
|
||||
});
|
||||
|
||||
sandbox.stub(api.tags, 'read').resolves({tags: tags});
|
||||
|
||||
sandbox.stub(urlService, 'owns');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
@ -65,7 +62,6 @@ describe('Unit - services/routing/helpers/fetch-data', function () {
|
||||
result.should.not.have.property('data');
|
||||
|
||||
result.posts.length.should.eql(posts.length);
|
||||
urlService.owns.called.should.be.false();
|
||||
|
||||
api.posts.browse.calledOnce.should.be.true();
|
||||
api.posts.browse.firstCall.args[0].should.be.an.Object();
|
||||
@ -102,7 +98,6 @@ describe('Unit - services/routing/helpers/fetch-data', function () {
|
||||
|
||||
result.posts.length.should.eql(posts.length);
|
||||
result.data.featured.posts.length.should.eql(posts.length);
|
||||
urlService.owns.called.should.be.false();
|
||||
|
||||
api.posts.browse.calledTwice.should.be.true();
|
||||
api.posts.browse.firstCall.args[0].should.have.property('include', 'author,authors,tags');
|
||||
@ -138,7 +133,6 @@ describe('Unit - services/routing/helpers/fetch-data', function () {
|
||||
|
||||
result.posts.length.should.eql(posts.length);
|
||||
result.data.featured.posts.length.should.eql(posts.length);
|
||||
urlService.owns.called.should.be.false();
|
||||
|
||||
api.posts.browse.calledTwice.should.be.true();
|
||||
api.posts.browse.firstCall.args[0].should.have.property('include', 'author,authors,tags');
|
||||
@ -172,7 +166,6 @@ describe('Unit - services/routing/helpers/fetch-data', function () {
|
||||
|
||||
result.posts.length.should.eql(posts.length);
|
||||
result.data.tag.length.should.eql(tags.length);
|
||||
urlService.owns.called.should.be.false();
|
||||
|
||||
api.posts.browse.calledOnce.should.be.true();
|
||||
api.posts.browse.firstCall.args[0].should.have.property('include');
|
||||
@ -182,31 +175,4 @@ describe('Unit - services/routing/helpers/fetch-data', function () {
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should verify if post belongs to collection', function (done) {
|
||||
const pathOptions = {};
|
||||
|
||||
const routerOptions = {
|
||||
identifier: 'identifier',
|
||||
filter: 'featured:true'
|
||||
};
|
||||
|
||||
urlService.owns.withArgs('identifier', posts[0].url).returns(false);
|
||||
urlService.owns.withArgs('identifier', posts[1].url).returns(true);
|
||||
urlService.owns.withArgs('identifier', posts[2].url).returns(false);
|
||||
urlService.owns.withArgs('identifier', posts[3].url).returns(false);
|
||||
|
||||
helpers.fetchData(pathOptions, routerOptions).then(function (result) {
|
||||
should.exist(result);
|
||||
result.should.be.an.Object().with.properties('posts', 'meta');
|
||||
|
||||
result.posts.length.should.eql(1);
|
||||
urlService.owns.callCount.should.eql(4);
|
||||
|
||||
api.posts.browse.calledOnce.should.be.true();
|
||||
api.posts.browse.firstCall.args[0].should.have.property('include');
|
||||
api.posts.browse.firstCall.args[0].should.have.property('filter', 'featured:true');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ describe('Unit - services/routing/helpers/format-response', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('collection', function () {
|
||||
describe('entries', function () {
|
||||
it('should return posts and posts pagination as top level keys', function () {
|
||||
let formatted,
|
||||
data = {
|
||||
@ -35,7 +35,7 @@ describe('Unit - services/routing/helpers/format-response', function () {
|
||||
meta: {pagination: {}}
|
||||
};
|
||||
|
||||
formatted = helpers.formatResponse.collection(data);
|
||||
formatted = helpers.formatResponse.entries(data);
|
||||
|
||||
formatted.should.be.an.Object().with.properties('posts', 'pagination');
|
||||
formatted.posts.should.eql(data.posts);
|
||||
@ -50,7 +50,7 @@ describe('Unit - services/routing/helpers/format-response', function () {
|
||||
data: {tag: tags}
|
||||
};
|
||||
|
||||
formatted = helpers.formatResponse.collection(data);
|
||||
formatted = helpers.formatResponse.entries(data);
|
||||
|
||||
formatted.should.be.an.Object().with.properties('posts', 'pagination', 'tag');
|
||||
formatted.tag.should.eql(data.data.tag[0]);
|
||||
@ -69,7 +69,7 @@ describe('Unit - services/routing/helpers/format-response', function () {
|
||||
}
|
||||
};
|
||||
|
||||
formatted = helpers.formatResponse.collection(data);
|
||||
formatted = helpers.formatResponse.entries(data);
|
||||
|
||||
formatted.should.be.an.Object().with.properties('posts', 'pagination', 'featured');
|
||||
formatted.featured.should.be.an.Object().with.properties('posts', 'pagination');
|
||||
|
@ -13,44 +13,44 @@ describe('templates', function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('[private fn] getCollectionTemplateHierarchy', function () {
|
||||
describe('[private fn] getEntriesTemplateHierarchy', function () {
|
||||
it('should return just index for empty options', function () {
|
||||
_private.getCollectionTemplateHierarchy({}).should.eql(['index']);
|
||||
_private.getEntriesTemplateHierarchy({}).should.eql(['index']);
|
||||
});
|
||||
|
||||
it('should return just index if collection name is index', function () {
|
||||
_private.getCollectionTemplateHierarchy({name: 'index'}).should.eql(['index']);
|
||||
_private.getEntriesTemplateHierarchy({name: 'index'}).should.eql(['index']);
|
||||
});
|
||||
|
||||
it('should return custom templates even if the collection is index', function () {
|
||||
_private.getCollectionTemplateHierarchy({name: 'index', templates: ['something']}).should.eql(['something', 'index']);
|
||||
_private.getEntriesTemplateHierarchy({name: 'index', templates: ['something']}).should.eql(['something', 'index']);
|
||||
});
|
||||
|
||||
it('should return collection name', function () {
|
||||
_private.getCollectionTemplateHierarchy({name: 'podcast'}).should.eql(['podcast', 'index']);
|
||||
_private.getEntriesTemplateHierarchy({name: 'podcast'}).should.eql(['podcast', 'index']);
|
||||
});
|
||||
|
||||
it('should return custom templates', function () {
|
||||
_private.getCollectionTemplateHierarchy({name: 'podcast', templates: ['mozart']}).should.eql(['mozart', 'podcast', 'index']);
|
||||
_private.getEntriesTemplateHierarchy({name: 'podcast', templates: ['mozart']}).should.eql(['mozart', 'podcast', 'index']);
|
||||
});
|
||||
|
||||
it('should return just index if collection name is index even if slug is set', function () {
|
||||
_private.getCollectionTemplateHierarchy({name: 'index', slugTemplate: true}, {slugParam: 'test'}).should.eql(['index']);
|
||||
_private.getEntriesTemplateHierarchy({name: 'index', slugTemplate: true}, {slugParam: 'test'}).should.eql(['index']);
|
||||
});
|
||||
|
||||
it('should return collection, index if collection has name', function () {
|
||||
_private.getCollectionTemplateHierarchy({name: 'tag'}).should.eql(['tag', 'index']);
|
||||
_private.getEntriesTemplateHierarchy({name: 'tag'}).should.eql(['tag', 'index']);
|
||||
});
|
||||
|
||||
it('should return collection-slug, collection, index if collection has name & slug + slugTemplate set', function () {
|
||||
_private.getCollectionTemplateHierarchy({
|
||||
_private.getEntriesTemplateHierarchy({
|
||||
name: 'tag',
|
||||
slugTemplate: true
|
||||
}, {slugParam: 'test'}).should.eql(['tag-test', 'tag', 'index']);
|
||||
});
|
||||
|
||||
it('should return front, collection-slug, collection, index if name, slugParam+slugTemplate & frontPageTemplate+pageParam=1 is set', function () {
|
||||
_private.getCollectionTemplateHierarchy({
|
||||
_private.getEntriesTemplateHierarchy({
|
||||
name: 'tag',
|
||||
slugTemplate: true,
|
||||
frontPageTemplate: 'front-tag'
|
||||
@ -58,14 +58,14 @@ describe('templates', function () {
|
||||
});
|
||||
|
||||
it('should return home, index for index collection if front is set and pageParam = 1', function () {
|
||||
_private.getCollectionTemplateHierarchy({
|
||||
_private.getEntriesTemplateHierarchy({
|
||||
name: 'index',
|
||||
frontPageTemplate: 'home'
|
||||
}, {path: '/'}).should.eql(['home', 'index']);
|
||||
});
|
||||
|
||||
it('should not use frontPageTemplate if not / collection', function () {
|
||||
_private.getCollectionTemplateHierarchy({
|
||||
_private.getEntriesTemplateHierarchy({
|
||||
name: 'index',
|
||||
frontPageTemplate: 'home'
|
||||
}, {path: '/magic/'}).should.eql(['index']);
|
||||
@ -254,7 +254,7 @@ describe('templates', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('[private fn] getTemplateForCollection', function () {
|
||||
describe('[private fn] getTemplateForEntries', function () {
|
||||
beforeEach(function () {
|
||||
hasTemplateStub = sandbox.stub().returns(false);
|
||||
|
||||
@ -270,7 +270,7 @@ describe('templates', function () {
|
||||
});
|
||||
|
||||
it('will return correct view for a tag', function () {
|
||||
var view = _private.getTemplateForCollection({name: 'tag', slugTemplate: true}, {slugParam: 'development'});
|
||||
var view = _private.getTemplateForEntries({name: 'tag', slugTemplate: true}, {slugParam: 'development'});
|
||||
should.exist(view);
|
||||
view.should.eql('index');
|
||||
});
|
||||
@ -285,20 +285,20 @@ describe('templates', function () {
|
||||
});
|
||||
|
||||
it('will return correct view for a tag', function () {
|
||||
var view = _private.getTemplateForCollection({name: 'tag', slugTemplate: true}, {slugParam: 'design'});
|
||||
var view = _private.getTemplateForEntries({name: 'tag', slugTemplate: true}, {slugParam: 'design'});
|
||||
should.exist(view);
|
||||
view.should.eql('tag-design');
|
||||
});
|
||||
|
||||
it('will return correct view for a tag', function () {
|
||||
var view = _private.getTemplateForCollection({name: 'tag', slugTemplate: true}, {slugParam: 'development'});
|
||||
var view = _private.getTemplateForEntries({name: 'tag', slugTemplate: true}, {slugParam: 'development'});
|
||||
should.exist(view);
|
||||
view.should.eql('tag');
|
||||
});
|
||||
});
|
||||
|
||||
it('will fall back to index even if no index.hbs', function () {
|
||||
var view = _private.getTemplateForCollection({name: 'tag', slugTemplate: true}, {slugParam: 'development'});
|
||||
var view = _private.getTemplateForEntries({name: 'tag', slugTemplate: true}, {slugParam: 'development'});
|
||||
should.exist(view);
|
||||
view.should.eql('index');
|
||||
});
|
||||
@ -395,7 +395,7 @@ describe('templates', function () {
|
||||
|
||||
stubs.pickTemplate = sandbox.stub(_private, 'pickTemplate').returns('testFromPickTemplate');
|
||||
stubs.getTemplateForEntry = sandbox.stub(_private, 'getTemplateForEntry').returns('testFromEntry');
|
||||
stubs.getTemplateForCollection = sandbox.stub(_private, 'getTemplateForCollection').returns('testFromCollection');
|
||||
stubs.getTemplateForEntries = sandbox.stub(_private, 'getTemplateForEntries').returns('testFromEntries');
|
||||
stubs.getTemplateForError = sandbox.stub(_private, 'getTemplateForError').returns('testFromError');
|
||||
});
|
||||
|
||||
@ -412,7 +412,7 @@ describe('templates', function () {
|
||||
// And nothing got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForCollection.called.should.be.false();
|
||||
stubs.getTemplateForEntries.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
});
|
||||
|
||||
@ -428,7 +428,7 @@ describe('templates', function () {
|
||||
// And nothing got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForCollection.called.should.be.false();
|
||||
stubs.getTemplateForEntries.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
});
|
||||
|
||||
@ -448,7 +448,7 @@ describe('templates', function () {
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.true();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForCollection.called.should.be.false();
|
||||
stubs.getTemplateForEntries.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.pickTemplate.calledWith('test', 'path/to/local/test.hbs').should.be.true();
|
||||
@ -470,7 +470,7 @@ describe('templates', function () {
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.true();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForCollection.called.should.be.false();
|
||||
stubs.getTemplateForEntries.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.pickTemplate.calledWith('test', 'path/to/local/test.hbs').should.be.true();
|
||||
@ -493,13 +493,13 @@ describe('templates', function () {
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.true();
|
||||
stubs.getTemplateForCollection.called.should.be.false();
|
||||
stubs.getTemplateForEntries.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.getTemplateForEntry.calledWith({slug: 'test'}).should.be.true();
|
||||
});
|
||||
|
||||
it('calls getTemplateForCollection for type collection', function () {
|
||||
it('calls getTemplateForEntries for type collection', function () {
|
||||
req.url = '/';
|
||||
req.params = {};
|
||||
|
||||
@ -512,15 +512,39 @@ describe('templates', function () {
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
res._template.should.eql('testFromCollection');
|
||||
res._template.should.eql('testFromEntries');
|
||||
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForCollection.called.should.be.true();
|
||||
stubs.getTemplateForEntries.called.should.be.true();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.getTemplateForCollection.calledWith({testCollection: 'test'}).should.be.true();
|
||||
stubs.getTemplateForEntries.calledWith({testCollection: 'test'}).should.be.true();
|
||||
});
|
||||
|
||||
it('calls getTemplateForEntries for type channel', function () {
|
||||
req.url = '/';
|
||||
req.params = {};
|
||||
|
||||
res._route = {
|
||||
type: 'channel'
|
||||
};
|
||||
|
||||
res.locals.routerOptions = {testChannel: 'test'};
|
||||
|
||||
// Call setTemplate
|
||||
templates.setTemplate(req, res, data);
|
||||
|
||||
res._template.should.eql('testFromEntries');
|
||||
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForEntries.called.should.be.true();
|
||||
stubs.getTemplateForError.called.should.be.false();
|
||||
|
||||
stubs.getTemplateForEntries.calledWith({testChannel: 'test'}).should.be.true();
|
||||
});
|
||||
|
||||
it('calls getTemplateForError if there is an error', function () {
|
||||
@ -544,7 +568,7 @@ describe('templates', function () {
|
||||
// Only pickTemplate got called
|
||||
stubs.pickTemplate.called.should.be.false();
|
||||
stubs.getTemplateForEntry.called.should.be.false();
|
||||
stubs.getTemplateForCollection.called.should.be.false();
|
||||
stubs.getTemplateForEntries.called.should.be.false();
|
||||
stubs.getTemplateForError.called.should.be.true();
|
||||
|
||||
stubs.getTemplateForError.calledWith(404).should.be.true();
|
||||
|
@ -0,0 +1 @@
|
||||
channel2
|
@ -0,0 +1 @@
|
||||
channel3
|
@ -0,0 +1,28 @@
|
||||
{{#foreach posts}}
|
||||
<article class="post-card {{post_class}}{{#unless feature_image}} no-image{{/unless}}">
|
||||
{{#if feature_image}}
|
||||
<a class="post-card-image-link" href="{{url}}">
|
||||
<div class="post-card-image" style="background-image: url({{feature_image}})"></div>
|
||||
</a>
|
||||
{{/if}}
|
||||
<div class="post-card-content">
|
||||
<a class="post-card-content-link" href="{{url}}">
|
||||
<header class="post-card-header">
|
||||
{{#if primary_tag}}
|
||||
<span class="post-card-tags">{{primary_tag.name}}</span>
|
||||
{{/if}}
|
||||
<h2 class="post-card-title">{{title}}</h2>
|
||||
</header>
|
||||
<section class="post-card-excerpt">
|
||||
<p>{{excerpt words="33"}}</p>
|
||||
</section>
|
||||
</a>
|
||||
<footer class="post-card-meta">
|
||||
{{#if author.profile_image}}
|
||||
<img class="author-profile-image" src="{{author.profile_image}}" alt="{{author.name}}" />
|
||||
{{/if}}
|
||||
<span class="post-card-author">{{author}}</span>
|
||||
</footer>
|
||||
</div>
|
||||
</article>
|
||||
{{/foreach}}
|
1
core/test/utils/fixtures/themes/test-theme/index.hbs
Normal file
1
core/test/utils/fixtures/themes/test-theme/index.hbs
Normal file
@ -0,0 +1 @@
|
||||
<div class="slug">{{tag.slug}}</div>
|
Loading…
Reference in New Issue
Block a user