Started moving meta data fetching to functions.

issue #6186
- Moved asset helper logic to a asset url function.
- Created author image function to be used in ghost_head helper.
- Created author url function to be used in the ghost_head helper.
- Created canonical url function to be used in the ghost_head helper.
- Moved meta_description helper logic to a function.
- Moved excerpt helper logic to a function.
- Created an index in data/meta to be used in ghost_head helper to get all data.
- Created keyword function to be used in the ghost_head helper.
- Created modified data function to be used in the ghost_head helper.
- Created next url function to be used in the ghost_head helper.
- Created ogType function to be used in the ghost_head helper.
- Created previous url function to be used in the ghost_head helper.
- Created published data function to be used in the ghost_head helper.
- Created rss url function to be used in the ghost_head helper.
- Created schema function to be used in the ghost_head helper.
- Created structured data function to be used in the ghost_head helper.
- Moved meta_title helper logic to a title function.
- Moved url helper logic to a url function.
- Wrote tests for all the new functions

This is just the first step. I plan on refactoring the ghost head to use these new functions.
This commit is contained in:
JT Turner 2016-01-17 02:07:52 -08:00
parent 57ae36ab21
commit 1f4c01d207
43 changed files with 1715 additions and 135 deletions

View File

@ -196,6 +196,10 @@ var _ = require('lodash'),
src: ['core/test/unit/server_helpers/*_spec.js']
},
metadata: {
src: ['core/test/unit/metadata/*_spec.js']
},
middleware: {
src: ['core/test/unit/middleware/*_spec.js']
},

View File

@ -0,0 +1,33 @@
var config = require('../../config');
function getAssetUrl(context, isAdmin, minify) {
var output = '';
output += config.paths.subdir + '/';
if (!context.match(/^favicon\.ico$/) && !context.match(/^shared/) && !context.match(/^asset/)) {
if (isAdmin) {
output += 'ghost/';
} else {
output += 'assets/';
}
}
// Get rid of any leading slash on the context
context = context.replace(/^\//, '');
// replace ".foo" with ".min.foo" in production
if (minify) {
context = context.replace(/\.([^\.]*)$/, '.min.$1');
}
output += context;
if (!context.match(/^favicon\.ico$/)) {
output = output + '?v=' + config.assetHash;
}
return output;
}
module.exports = getAssetUrl;

View File

@ -0,0 +1,14 @@
var config = require('../../config');
function getAuthorImage(data, absolute) {
var context = data.context ? data.context[0] : null,
blog = config.theme,
contextObject = data[context] || blog;
if (context === 'post' && contextObject.author && contextObject.author.image) {
return config.urlFor('image', {image: contextObject.author.image}, absolute);
}
return null;
}
module.exports = getAuthorImage;

View File

@ -0,0 +1,14 @@
var config = require('../../config');
function getAuthorUrl(data, absolute) {
var context = data.context ? data.context[0] : null;
if (data.author) {
return config.urlFor('author', {author: data.author}, absolute);
}
if (data[context] && data[context].author) {
return config.urlFor('author', {author: data[context].author}, absolute);
}
return null;
}
module.exports = getAuthorUrl;

View File

@ -0,0 +1,9 @@
var config = require('../../config'),
getUrl = require('./url');
function getCanonicalUrl(data) {
return config.urlJoin(config.getBaseUrl(false),
getUrl(data, false));
}
module.exports = getCanonicalUrl;

View File

@ -0,0 +1,20 @@
var config = require('../../config');
function getCoverImage(data) {
var context = data.context ? data.context[0] : null,
blog = config.theme,
contextObject = data[context] || blog;
if (context === 'home' || context === 'author') {
if (contextObject.cover) {
return config.urlFor('image', {image: contextObject.cover}, true);
}
} else {
if (contextObject.image) {
return config.urlFor('image', {image: contextObject.image}, true);
}
}
return null;
}
module.exports = getCoverImage;

View File

@ -0,0 +1,25 @@
var _ = require('lodash'),
config = require('../../config');
function getDescription(data, root) {
var description = '',
context = root ? root.context : null;
if (data.meta_description) {
description = data.meta_description;
} else if (_.contains(context, 'paged')) {
description = '';
} else if (_.contains(context, 'home')) {
description = config.theme.description;
} else if (_.contains(context, 'author') && data.author) {
description = data.author.bio;
} else if (_.contains(context, 'tag') && data.tag) {
description = data.tag.meta_description;
} else if ((_.contains(context, 'post') || _.contains(context, 'page')) && data.post) {
description = data.post.meta_description;
}
return (description || '').trim();
}
module.exports = getDescription;

View File

@ -0,0 +1,19 @@
var downsize = require('downsize');
function getExcerpt(html, truncateOptions) {
// Strip inline and bottom footnotes
var excerpt = html.replace(/<a href="#fn.*?rel="footnote">.*?<\/a>/gi, '');
excerpt = excerpt.replace(/<div class="footnotes"><ol>.*?<\/ol><\/div>/, '');
// Strip other html
excerpt = excerpt.replace(/<\/?[^>]+>/gi, '');
excerpt = excerpt.replace(/(\r\n|\n|\r)+/gm, ' ');
/*jslint regexp:false */
if (!truncateOptions.words && !truncateOptions.characters) {
truncateOptions.words = 50;
}
return downsize(excerpt, truncateOptions);
}
module.exports = getExcerpt;

View File

@ -0,0 +1,46 @@
var config = require('../../config'),
getUrl = require('./url'),
getCanonicalUrl = require('./canonical_url'),
getPreviousUrl = require('./previous_url'),
getNextUrl = require('./next_url'),
getAuthorUrl = require('./author_url'),
getRssUrl = require('./rss_url'),
getTitle = require('./title'),
getDescription = require('./description'),
getCoverImage = require('./cover_image'),
getAuthorImage = require('./author_image'),
getKeywords = require('./keywords'),
getPublishedDate = require('./published_date'),
getModifiedDate = require('./modified_date'),
getOgType = require('./og_type'),
getStructuredData = require('./structured_data'),
getPostSchema = require('./schema');
function getMetaData(data, root) {
var blog = config.theme, metaData;
metaData = {
url: getUrl(data, true),
canonicalUrl: getCanonicalUrl(data),
previousUrl: getPreviousUrl(data, true),
nextUrl: getNextUrl(data, true),
authorUrl: getAuthorUrl(data, true),
rssUrl: getRssUrl(data, true),
metaTitle: getTitle(data, root),
metaDescription: getDescription(data, root),
coverImage: getCoverImage(data, true),
authorImage: getAuthorImage(data, true),
keywords: getKeywords(data),
publishedDate: getPublishedDate(data),
modifiedDate: getModifiedDate(data),
ogType: getOgType(data),
blog: blog
};
metaData.structuredData = getStructuredData(metaData);
metaData.schema = getPostSchema(metaData, data);
return metaData;
}
module.exports = getMetaData;

View File

@ -0,0 +1,10 @@
function getKeywords(data) {
if (data.post && data.post.tags && data.post.tags.length > 0) {
return data.post.tags.map(function (tag) {
return tag.name;
});
}
return null;
}
module.exports = getKeywords;

View File

@ -0,0 +1,13 @@
function getModifiedDate(data) {
var context = data.context ? data.context[0] : null,
modDate;
if (data[context]) {
modDate = data[context].updated_at || null;
if (modDate) {
return new Date(modDate).toISOString();
}
}
return null;
}
module.exports = getModifiedDate;

View File

@ -0,0 +1,23 @@
var config = require('../../config'),
trimmedUrlpattern = /.+(?=\/page\/\d*\/)/,
tagOrAuthorPattern = /\/(tag)|(author)\//;
function getNextUrl(data, absolute) {
var trimmedUrl, next;
if (data.relativeUrl) {
trimmedUrl = data.relativeUrl.match(trimmedUrlpattern);
if (data.pagination && data.pagination.next) {
next = '/page/' + data.pagination.next + '/';
if (trimmedUrl) {
next = trimmedUrl + next;
} else if (tagOrAuthorPattern.test(data.relativeUrl)) {
next = data.relativeUrl.slice(0, -1) + next;
}
return config.urlFor({relativeUrl: next, secure: data.secure}, absolute);
}
}
return null;
}
module.exports = getNextUrl;

View File

@ -0,0 +1,12 @@
function getOgType(data) {
var context = data.context ? data.context[0] : null;
if (context === 'author') {
return 'profile';
}
if (context === 'post') {
return 'article';
}
return 'website';
}
module.exports = getOgType;

View File

@ -0,0 +1,18 @@
var config = require('../../config'),
trimmedUrlpattern = /.+(?=\/page\/\d*\/)/;
function getPreviousUrl(data, absolute) {
var trimmedUrl, prev;
if (data.relativeUrl) {
trimmedUrl = data.relativeUrl.match(trimmedUrlpattern);
if (data.pagination && data.pagination.prev) {
prev = (data.pagination.prev > 1 ? '/page/' + data.pagination.prev + '/' : '/');
prev = (trimmedUrl) ? trimmedUrl + prev : prev;
return config.urlFor({relativeUrl: prev, secure: data.secure}, absolute);
}
}
return null;
}
module.exports = getPreviousUrl;

View File

@ -0,0 +1,13 @@
function getPublishedDate(data) {
var context = data.context ? data.context[0] : null,
pubDate;
if (data[context]) {
pubDate = data[context].published_at || data[context].created_at || null;
if (pubDate) {
return new Date(pubDate).toISOString();
}
}
return null;
}
module.exports = getPublishedDate;

View File

@ -0,0 +1,7 @@
var config = require('../../config');
function getRssUrl(data, absolute) {
return config.urlFor('rss', {secure: data.secure}, absolute);
}
module.exports = getRssUrl;

View File

@ -0,0 +1,111 @@
var config = require('../../config'),
hbs = require('express-hbs'),
escapeExpression = hbs.handlebars.Utils.escapeExpression,
_ = require('lodash');
// Creates the final schema object with values that are not null
function trimSchema(schema) {
var schemaObject = {};
_.each(schema, function (value, key) {
if (value !== null && typeof value !== 'undefined') {
schemaObject[key] = value;
}
});
return schemaObject;
}
function getPostSchema(metaData, data) {
var schema = {
'@context': 'http://schema.org',
'@type': 'Article',
publisher: metaData.blog.title,
author: {
'@type': 'Person',
name: escapeExpression(data.post.author.name),
image: metaData.authorImage,
url: metaData.authorUrl,
sameAs: data.post.author.website || null,
description: data.post.author.bio ?
escapeExpression(data.post.author.bio) :
null
},
headline: escapeExpression(metaData.metaTitle),
url: metaData.url,
datePublished: metaData.publishedDate,
dateModified: metaData.modifiedDate,
image: metaData.coverImage,
keywords: metaData.keywords && metaData.keywords.length > 0 ?
metaData.keywords.join(', ') : null,
description: metaData.metaDescription ?
escapeExpression(metaData.metaDescription) :
null
};
schema.author = trimSchema(schema.author);
return trimSchema(schema);
}
function getHomeSchema(metaData) {
var schema = {
'@context': 'http://schema.org',
'@type': 'Website',
publisher: escapeExpression(metaData.blog.title),
url: metaData.url,
image: metaData.coverImage,
description: metaData.metaDescription ?
escapeExpression(metaData.metaDescription) :
null
};
return trimSchema(schema);
}
function getTagSchema(metaData, data) {
var schema = {
'@context': 'http://schema.org',
'@type': 'Series',
publisher: escapeExpression(metaData.blog.title),
url: metaData.url,
image: metaData.coverImage,
name: data.tag.name,
description: metaData.metaDescription ?
escapeExpression(metaData.metaDescription) :
null
};
return trimSchema(schema);
}
function getAuthorSchema(metaData, data) {
var schema = {
'@context': 'http://schema.org',
'@type': 'Person',
sameAs: data.author.website || null,
publisher: escapeExpression(metaData.blog.title),
name: escapeExpression(data.author.name),
url: metaData.authorUrl,
image: metaData.coverImage,
description: metaData.metaDescription ?
escapeExpression(metaData.metaDescription) :
null
};
return trimSchema(schema);
}
function getSchema(metaData, data) {
if (!config.isPrivacyDisabled('useStructuredData')) {
var context = data.context ? data.context[0] : null;
if (context === 'post') {
return getPostSchema(metaData, data);
} else if (context === 'home') {
return getHomeSchema(metaData);
} else if (context === 'tag') {
return getTagSchema(metaData, data);
} else if (context === 'author') {
return getAuthorSchema(metaData, data);
}
}
return null;
}
module.exports = getSchema;

View File

@ -0,0 +1,36 @@
function getStructuredData(metaData) {
var structuredData,
card = 'summary';
if (metaData.coverImage) {
card = 'summary_large_image';
}
structuredData = {
'og:site_name': metaData.blog.title,
'og:type': metaData.ogType,
'og:title': metaData.metaTitle,
'og:description': metaData.metaDescription,
'og:url': metaData.canonicalUrl,
'og:image': metaData.coverImage,
'article:published_time': metaData.publishedDate,
'article:modified_time': metaData.modifiedDate,
'article:tag': metaData.keywords,
'twitter:card': card,
'twitter:title': metaData.metaTitle,
'twitter:description': metaData.metaDescription,
'twitter:url': metaData.canonicalUrl,
'twitter:image:src': metaData.coverImage
};
// return structored data removing null or undefined keys
return Object.keys(structuredData).reduce(function (data, key) {
var content = structuredData[key];
if (content !== null && typeof content !== 'undefined') {
data[key] = content;
}
return data;
}, {});
}
module.exports = getStructuredData;

View File

@ -0,0 +1,31 @@
var _ = require('lodash'),
config = require('../../config');
function getTitle(data, root) {
var title = '',
context = root ? root.context : null,
blog = config.theme,
pagination = root ? root.pagination : null,
pageString = '';
if (pagination && pagination.total > 1) {
pageString = ' - Page ' + pagination.page;
}
if (data.meta_title) {
title = data.meta_title;
} else if (_.contains(context, 'home')) {
title = blog.title;
} else if (_.contains(context, 'author') && data.author) {
title = data.author.name + pageString + ' - ' + blog.title;
} else if (_.contains(context, 'tag') && data.tag) {
title = data.tag.meta_title || data.tag.name + pageString + ' - ' + blog.title;
} else if ((_.contains(context, 'post') || _.contains(context, 'page')) && data.post) {
title = data.post.meta_title || data.post.title;
} else {
title = blog.title + pageString;
}
return (title || '').trim();
}
module.exports = getTitle;

View File

@ -0,0 +1,24 @@
var schema = require('../schema').checks,
config = require('../../config');
function getUrl(data, absolute) {
if (schema.isPost(data)) {
return config.urlFor('post', {post: data, secure: data.secure}, absolute);
}
if (schema.isTag(data)) {
return config.urlFor('tag', {tag: data, secure: data.secure}, absolute);
}
if (schema.isUser(data)) {
return config.urlFor('author', {author: data, secure: data.secure}, absolute);
}
if (schema.isNav(data)) {
return config.urlFor('nav', {nav: data, secure: data.secure}, absolute);
}
return config.urlFor(data, {}, absolute);
}
module.exports = getUrl;

View File

@ -3,49 +3,23 @@
//
// Returns the path to the specified asset. The ghost flag outputs the asset path for the Ghost admin
var hbs = require('express-hbs'),
config = require('../config'),
utils = require('./utils'),
asset;
var getAssetUrl = require('../data/meta/asset_url'),
hbs = require('express-hbs');
asset = function (context, options) {
var output = '',
isAdmin,
function asset(context, options) {
var isAdmin,
minify;
if (options && options.hash) {
isAdmin = options.hash.ghost;
minify = options.hash.minifyInProduction;
}
output += config.paths.subdir + '/';
if (!context.match(/^favicon\.ico$/) && !context.match(/^shared/) && !context.match(/^asset/)) {
if (isAdmin) {
output += 'ghost/';
} else {
output += 'assets/';
}
if (process.env.NODE_ENV !== 'production') {
minify = false;
}
// Get rid of any leading slash on the context
context = context.replace(/^\//, '');
// replace ".foo" with ".min.foo" in production
if (utils.isProduction && minify) {
context = context.replace('.', '.min.');
}
output += context;
if (!context.match(/^favicon\.ico$/)) {
output = utils.assetTemplate({
source: output,
version: config.assetHash
});
}
return new hbs.handlebars.SafeString(output);
};
return new hbs.handlebars.SafeString(
getAssetUrl(context, isAdmin, minify)
);
}
module.exports = asset;

View File

@ -5,37 +5,21 @@
//
// Defaults to words="50"
var hbs = require('express-hbs'),
_ = require('lodash'),
downsize = require('downsize'),
excerpt;
var hbs = require('express-hbs'),
_ = require('lodash'),
getMetaDataExcerpt = require('../data/meta/excerpt');
excerpt = function (options) {
var truncateOptions = (options || {}).hash || {},
excerpt;
function excerpt(options) {
var truncateOptions = (options || {}).hash || {};
truncateOptions = _.pick(truncateOptions, ['words', 'characters']);
_.keys(truncateOptions).map(function (key) {
truncateOptions[key] = parseInt(truncateOptions[key], 10);
});
/*jslint regexp:true */
excerpt = String(this.html);
// Strip inline and bottom footnotes
excerpt = excerpt.replace(/<a href="#fn.*?rel="footnote">.*?<\/a>/gi, '');
excerpt = excerpt.replace(/<div class="footnotes"><ol>.*?<\/ol><\/div>/, '');
// Strip other html
excerpt = excerpt.replace(/<\/?[^>]+>/gi, '');
excerpt = excerpt.replace(/(\r\n|\n|\r)+/gm, ' ');
/*jslint regexp:false */
if (!truncateOptions.words && !truncateOptions.characters) {
truncateOptions.words = 50;
}
return new hbs.handlebars.SafeString(
downsize(excerpt, truncateOptions)
getMetaDataExcerpt(String(this.html), truncateOptions)
);
};
}
module.exports = excerpt;

View File

@ -6,31 +6,12 @@
// We use the name meta_description to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var _ = require('lodash'),
config = require('../config'),
meta_description;
var getMetaDataDescription = require('../data/meta/description');
meta_description = function (options) {
function meta_description(options) {
options = options || {};
var context = options.data.root.context,
description;
if (this.meta_description) {
description = this.meta_description; // E.g. in {{#foreach}}
} else if (_.contains(context, 'paged')) {
description = '';
} else if (_.contains(context, 'home')) {
description = config.theme.description;
} else if (_.contains(context, 'author') && this.author) {
description = this.author.bio;
} else if (_.contains(context, 'tag') && this.tag) {
description = this.tag.meta_description;
} else if ((_.contains(context, 'post') || _.contains(context, 'page')) && this.post) {
description = this.post.meta_description;
}
return (description || '').trim();
};
return getMetaDataDescription(this, options.data.root) || '';
}
module.exports = meta_description;

View File

@ -6,37 +6,10 @@
// We use the name meta_title to match the helper for consistency:
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
var _ = require('lodash'),
config = require('../config'),
meta_title;
var getMetaDataTitle = require('../data/meta/title');
meta_title = function (options) {
/*jshint unused:false*/
var title = '',
context = options.data.root.context,
blog = config.theme,
pagination = options.data.root.pagination,
pageString = '';
if (pagination && pagination.total > 1) {
pageString = ' - Page ' + pagination.page;
}
if (this.meta_title) {
title = this.meta_title; // E.g. in {{#foreach}}
} else if (_.contains(context, 'home')) {
title = blog.title;
} else if (_.contains(context, 'author') && this.author) {
title = this.author.name + pageString + ' - ' + blog.title;
} else if (_.contains(context, 'tag') && this.tag) {
title = this.tag.meta_title || this.tag.name + pageString + ' - ' + blog.title;
} else if ((_.contains(context, 'post') || _.contains(context, 'page')) && this.post) {
title = this.post.meta_title || this.post.title;
} else {
title = blog.title + pageString;
}
return (title || '').trim();
};
function meta_title(options) {
return getMetaDataTitle(this, options.data.root);
}
module.exports = meta_title;

View File

@ -4,30 +4,12 @@
// Returns the URL for the current object scope i.e. If inside a post scope will return post permalink
// `absolute` flag outputs absolute URL, else URL is relative
var config = require('../config'),
schema = require('../data/schema').checks,
url;
var getMetaDataUrl = require('../data/meta/url');
url = function (options) {
function url(options) {
var absolute = options && options.hash.absolute;
if (schema.isPost(this)) {
return config.urlFor('post', {post: this, secure: this.secure}, absolute);
}
if (schema.isTag(this)) {
return config.urlFor('tag', {tag: this, secure: this.secure}, absolute);
}
if (schema.isUser(this)) {
return config.urlFor('author', {author: this, secure: this.secure}, absolute);
}
if (schema.isNav(this)) {
return config.urlFor('nav', {nav: this, secure: this.secure}, absolute);
}
return config.urlFor(this, {}, absolute);
};
return getMetaDataUrl(this, absolute);
}
module.exports = url;

View File

@ -0,0 +1,45 @@
/*globals describe, it*/
var getAssetUrl = require('../../../server/data/meta/asset_url'),
config = require('../../../server/config');
describe('getAssetUrl', function () {
it('should return asset url with just context', function () {
var testUrl = getAssetUrl('myfile.js');
testUrl.should.equal('/assets/myfile.js?v=' + config.assetHash);
});
it('should return asset url with just context even with leading /', function () {
var testUrl = getAssetUrl('/myfile.js');
testUrl.should.equal('/assets/myfile.js?v=' + config.assetHash);
});
it('should return ghost url if is admin', function () {
var testUrl = getAssetUrl('myfile.js', true);
testUrl.should.equal('/ghost/myfile.js?v=' + config.assetHash);
});
it('should not add ghost to url if is admin and has asset in context', function () {
var testUrl = getAssetUrl('asset/myfile.js', true);
testUrl.should.equal('/asset/myfile.js?v=' + config.assetHash);
});
it('should not add ghost or asset to url if favicon.ico', function () {
var testUrl = getAssetUrl('favicon.ico');
testUrl.should.equal('/favicon.ico');
});
it('should not add ghost or asset to url has shared in it', function () {
var testUrl = getAssetUrl('shared/myfile.js');
testUrl.should.equal('/shared/myfile.js?v=' + config.assetHash);
});
it('should return asset minified url when minify true', function () {
var testUrl = getAssetUrl('myfile.js', false, true);
testUrl.should.equal('/assets/myfile.min.js?v=' + config.assetHash);
});
it('should not add min to anything besides the last .', function () {
var testUrl = getAssetUrl('test.page/myfile.js', false, true);
testUrl.should.equal('/assets/test.page/myfile.min.js?v=' + config.assetHash);
});
});

View File

@ -0,0 +1,76 @@
/*globals describe, it*/
var getAuthorImage = require('../../../server/data/meta/author_image'),
should = require('should'),
config = require('../../../server/config');
describe('getAuthorImage', function () {
it('should return author image url if post and has url',
function () {
var imageUrl = getAuthorImage({
context: ['post'],
post: {
author: {
image: '/content/images/2016/01/myimage.jpg'
}
}
}, false);
imageUrl.should.equal('/content/images/2016/01/myimage.jpg');
});
it('should return absolute author image url if post and has url',
function () {
var imageUrl = getAuthorImage({
context: ['post'],
post: {
author: {
image: '/content/images/2016/01/myimage.jpg'
}
}
}, true);
imageUrl.should.not.equal('/content/images/2016/01/myimage.jpg');
imageUrl.should.match(/\/content\/images\/2016\/01\/myimage\.jpg$/);
});
it('should return null if context does not contain author image url and is a post',
function () {
var imageUrl = getAuthorImage({
context: ['post'],
post: {
author: {
name: 'Test Author'
}
}
});
should(imageUrl).equal(null);
});
it('should return null if context does not contain author and is a post', function () {
var imageUrl = getAuthorImage({
context: ['post'],
post: {}
});
should(imageUrl).equal(null);
});
it('should return null if context is not a post', function () {
var imageUrl = getAuthorImage({
context: ['tag']
});
should(imageUrl).equal(null);
});
it('should return config theme auther image if context is a post and no post',
function () {
config.set({
theme: {
author: {
image: '/content/images/2016/01/myimage.jpg'
}
}
});
var imageUrl = getAuthorImage({
context: ['post']
});
imageUrl.should.match(/\/content\/images\/2016\/01\/myimage\.jpg$/);
});
});

View File

@ -0,0 +1,59 @@
/*globals describe, it*/
var getAuthorUrl = require('../../../server/data/meta/author_url'),
should = require('should');
describe('getAuthorUrl', function () {
it('should return author url if context contains author',
function () {
var authorUrl = getAuthorUrl({
context: ['post'],
post: {
author: {
slug: 'test-author'
}
}
});
authorUrl.should.equal('/author/test-author/');
});
it('should return absolute author url if context contains author',
function () {
var authorUrl = getAuthorUrl({
context: ['post'],
post: {
author: {
slug: 'test-author'
}
}
}, true);
authorUrl.should.not.equal('/author/test-author/');
authorUrl.should.match(/\/author\/test-author\/$/);
});
it('should return author url if data contains author',
function () {
var authorUrl = getAuthorUrl({
author: {
slug: 'test-author'
}
});
authorUrl.should.equal('/author/test-author/');
});
it('should return absolute author url if data contains author',
function () {
var authorUrl = getAuthorUrl({
author: {
slug: 'test-author'
}
}, true);
authorUrl.should.not.equal('/author/test-author/');
authorUrl.should.match(/\/author\/test-author\/$/);
});
it('should return null if no author on data or context',
function () {
var authorUrl = getAuthorUrl({}, true);
should(authorUrl).equal(null);
});
});

View File

@ -0,0 +1,55 @@
/*globals describe, it*/
var getCanonicalUrl = require('../../../server/data/meta/canonical_url');
describe('getCanonicalUrl', function () {
it('should return absolute canonical url for post', function () {
var canonicalUrl = getCanonicalUrl({
url: '/this-is-a-test-post/',
html: '<h1>Test 123</h1>',
markdown: '# Test 123',
title: 'This is a test post',
slug: 'this-is-a-test-post',
secure: true
});
canonicalUrl.should.not.equal('/this-is-a-test-post/');
canonicalUrl.should.match(/\/this-is-a-test-post\/$/);
canonicalUrl.should.not.match(/^https:/);
});
it('should return absolute canonical url for tag', function () {
var canonicalUrl = getCanonicalUrl({
parent: null,
name: 'testing',
slug: 'testing',
description: 'We need testing',
secure: true
});
canonicalUrl.should.not.equal('/tag/testing/');
canonicalUrl.should.match(/\/tag\/testing\/$/);
canonicalUrl.should.not.match(/^https:/);
});
it('should return absolute canonical url for author', function () {
var canonicalUrl = getCanonicalUrl({
name: 'Test User',
bio: 'This is all about testing',
website: 'http://my-testing-site.com',
status: 'testing',
location: 'Wounderland',
slug: 'test-user',
secure: true
});
canonicalUrl.should.not.equal('/author/test-user/');
canonicalUrl.should.match(/\/author\/test-user\/$/);
canonicalUrl.should.not.match(/^https:/);
});
it('should return home if empty secure data', function () {
var canonicalUrl = getCanonicalUrl({
secure: true
});
canonicalUrl.should.not.equal('/');
canonicalUrl.should.match(/\/$/);
canonicalUrl.should.not.match(/^https:/);
});
});

View File

@ -0,0 +1,62 @@
/*globals describe, it*/
var getCoverImage = require('../../../server/data/meta/cover_image'),
should = require('should');
describe('getCoverImage', function () {
it('should return absolute cover image url for home', function () {
var coverImageUrl = getCoverImage({
context: ['home'],
home: {
cover: '/content/images/my-test-image.jpg'
}
});
coverImageUrl.should.not.equal('/content/images/my-test-image.jpg');
coverImageUrl.should.match(/\/content\/images\/my-test-image\.jpg$/);
});
it('should return absolute cover image url for author', function () {
var coverImageUrl = getCoverImage({
context: ['author'],
author: {
cover: '/content/images/my-test-image.jpg'
}
});
coverImageUrl.should.not.equal('/content/images/my-test-image.jpg');
coverImageUrl.should.match(/\/content\/images\/my-test-image\.jpg$/);
});
it('should return absolute image url for post', function () {
var coverImageUrl = getCoverImage({
context: ['post'],
post: {
image: '/content/images/my-test-image.jpg'
}
});
coverImageUrl.should.not.equal('/content/images/my-test-image.jpg');
coverImageUrl.should.match(/\/content\/images\/my-test-image\.jpg$/);
});
it('should return null if missing image', function () {
var coverImageUrl = getCoverImage({
context: ['post'],
post: {}
});
should(coverImageUrl).equal(null);
});
it('should return null if author missing cover', function () {
var coverImageUrl = getCoverImage({
context: ['author'],
author: {}
});
should(coverImageUrl).equal(null);
});
it('should return null if home missing cover', function () {
var coverImageUrl = getCoverImage({
context: ['home'],
home: {}
});
should(coverImageUrl).equal(null);
});
});

View File

@ -0,0 +1,62 @@
/*globals describe, it*/
var getMetaDescription = require('../../../server/data/meta/description');
describe('getMetaDescription', function () {
it('should return meta_description if on data root', function () {
var description = getMetaDescription({
meta_description: 'My test description.'
});
description.should.equal('My test description.');
});
it('should return empty string if on root context contains paged', function () {
var description = getMetaDescription({}, {
context: ['paged']
});
description.should.equal('');
});
it('should return data author bio if on root context contains author', function () {
var description = getMetaDescription({
author: {
bio: 'Just some hack building code to make the world better.'
}
}, {
context: ['author']
});
description.should.equal('Just some hack building code to make the world better.');
});
it('should return data tag meta description if on root context contains tag', function () {
var description = getMetaDescription({
tag: {
meta_description: 'Best tag ever!'
}
}, {
context: ['tag']
});
description.should.equal('Best tag ever!');
});
it('should return data post meta description if on root context contains post', function () {
var description = getMetaDescription({
post: {
meta_description: 'Best post ever!'
}
}, {
context: ['post']
});
description.should.equal('Best post ever!');
});
it('should return data post meta description if on root context contains page', function () {
var description = getMetaDescription({
post: {
meta_description: 'Best page ever!'
}
}, {
context: ['page']
});
description.should.equal('Best page ever!');
});
});

View File

@ -0,0 +1,59 @@
/*globals describe, it*/
var getExcerpt = require('../../../server/data/meta/excerpt');
describe('getExcerpt', function () {
it('should return html excerpt with no html', function () {
var html = '<p>There are <br />10<br> types<br/> of people in <img src="a">the world:' +
'<img src=b alt="c"> those who <img src="@" onclick="javascript:alert(\'hello\');">' +
'understand trinary</p>, those who don\'t <div style="" class=~/\'-,._?!|#>and' +
'< test > those<<< test >>> who mistake it &lt;for&gt; binary.',
expected = 'There are 10 types of people in the world: those who understand trinary, those who ' +
'don\'t and those>> who mistake it &lt;for&gt; binary.';
getExcerpt(html, {}).should.equal(expected);
});
it('should return html excerpt strips multiple inline footnotes', function () {
var html = '<p>Testing<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>, ' +
'my footnotes. And stuff. Footnote<sup id="fnref:2"><a href="#fn:2" ' +
'rel="footnote">2</a></sup><a href="http://google.com">with a link</a> ' +
'right after.',
expected = 'Testing, my footnotes. And stuff. Footnotewith a link right after.';
getExcerpt(html, {}).should.equal(expected);
});
it('should return html excerpt striping inline and bottom footnotes', function () {
var html = '<p>Testing<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a>' +
'</sup> a very short post with a single footnote.</p>\n' +
'<div class="footnotes"><ol><li class="footnote" id="fn:1"><p>' +
'<a href="https://ghost.org">https://ghost.org</a> <a href="#fnref:1" ' +
'title="return to article">↩</a></p></li></ol></div>',
expected = 'Testing a very short post with a single footnote.';
getExcerpt(html, {}).should.equal(expected);
});
it('should return html excerpt truncated by word', function () {
var html = '<p>Hello <strong>World! It\'s me!</strong></p>',
expected = 'Hello World!';
getExcerpt(html, {words: '2'}).should.equal(expected);
});
it('should return html excerpt truncated by words with non-ascii characters',
function () {
var html = '<p>Едквюэ опортэат <strong>праэчынт ючю но, квуй эю</strong></p>',
expected = 'Едквюэ опортэат';
getExcerpt(html, {words: '2'}).should.equal(expected);
});
it('should return html excerpt truncated by character',
function () {
var html = '<p>Hello <strong>World! It\'s me!</strong></p>',
expected = 'Hello Wo';
getExcerpt(html, {characters: '8'}).should.equal(expected);
});
});

View File

@ -0,0 +1,41 @@
/*globals describe, it*/
var getKeywords = require('../../../server/data/meta/keywords'),
should = require('should');
describe('getKeywords', function () {
it('should return tags as keywords if post has tags', function () {
var keywords = getKeywords({
post: {
tags: [
{name: 'one'},
{name: 'two'},
{name: 'three'}
]
}
});
should.deepEqual(keywords, ['one', 'two', 'three']);
});
it('should return null if post has tags is empty array', function () {
var keywords = getKeywords({
post: {
tags: []
}
});
should.equal(keywords, null);
});
it('should return null if post has no tags', function () {
var keywords = getKeywords({
post: {}
});
should.equal(keywords, null);
});
it('should return null if not a post', function () {
var keywords = getKeywords({
author: {}
});
should.equal(keywords, null);
});
});

View File

@ -0,0 +1,33 @@
/*globals describe, it*/
var getModifiedDate = require('../../../server/data/meta/modified_date'),
should = require('should');
describe('getModifiedDate', function () {
it('should return updated at date as ISO 8601 from context if exists', function () {
var modDate = getModifiedDate({
context: ['post'],
post: {
updated_at: new Date('2016-01-01 12:56:45.232Z')
}
});
should.equal(modDate, '2016-01-01T12:56:45.232Z');
});
it('should return null if no update_at date on context', function () {
var modDate = getModifiedDate({
context: ['author'],
author: {}
});
should.equal(modDate, null);
});
it('should return null if context and property do not match in name', function () {
var modDate = getModifiedDate({
context: ['author'],
post: {
updated_at: new Date('2016-01-01 12:56:45.232Z')
}
});
should.equal(modDate, null);
});
});

View File

@ -0,0 +1,55 @@
/*globals describe, it*/
var getNextUrl = require('../../../server/data/meta/next_url'),
should = require('should');
describe('getNextUrl', function () {
it('should return next url if relative url and pagination next set', function () {
var nextUrl = getNextUrl({
relativeUrl: '/test/page/2/',
pagination: {
next: '3'
}
});
should.equal(nextUrl, '/test/page/3/');
});
it('should return next url if with / relative url', function () {
var nextUrl = getNextUrl({
relativeUrl: '/',
pagination: {
next: '2'
}
});
should.equal(nextUrl, '/page/2/');
});
it('should return absolute next url if relative url and pagination next set', function () {
var nextUrl = getNextUrl({
relativeUrl: '/test/page/2/',
pagination: {
next: '3'
}
}, true);
should.equal(nextUrl, 'http://127.0.0.1:2369/test/page/3/');
});
it('should return null if no pagination next', function () {
var nextUrl = getNextUrl({
relativeUrl: '/',
pagination: {
prev: '2'
}
});
should.equal(nextUrl, null);
});
it('should return null if no relative url', function () {
var nextUrl = getNextUrl({
relativeUrl: '',
pagination: {
next: '2'
}
});
should.equal(nextUrl, null);
});
});

View File

@ -0,0 +1,26 @@
/*globals describe, it*/
var getOgType = require('../../../server/data/meta/og_type'),
should = require('should');
describe('getOgType', function () {
it('should return og type profile if context is type author', function () {
var ogType = getOgType({
context: ['author']
});
should.equal(ogType, 'profile');
});
it('should return og type article if context is type post', function () {
var ogType = getOgType({
context: ['post']
});
should.equal(ogType, 'article');
});
it('should return og type website if context is not author or post', function () {
var ogType = getOgType({
context: ['tag']
});
should.equal(ogType, 'website');
});
});

View File

@ -0,0 +1,65 @@
/*globals describe, it*/
var getPreviousUrl = require('../../../server/data/meta/previous_url'),
should = require('should');
describe('getPreviousUrl', function () {
it('should return prev url if relative url and pagination prev set', function () {
var prevUrl = getPreviousUrl({
relativeUrl: '/test/page/3/',
pagination: {
prev: '2'
}
});
should.equal(prevUrl, '/test/page/2/');
});
it('should return prev url if with / relative url', function () {
var prevUrl = getPreviousUrl({
relativeUrl: '/',
pagination: {
prev: '2'
}
});
should.equal(prevUrl, '/page/2/');
});
it('should return prev url with no page is prev is 1', function () {
var prevUrl = getPreviousUrl({
relativeUrl: '/page/2/',
pagination: {
prev: '1'
}
});
should.equal(prevUrl, '/');
});
it('should return absolute prev url if relative url and pagination prev set', function () {
var prevUrl = getPreviousUrl({
relativeUrl: '/test/page/2/',
pagination: {
prev: '3'
}
}, true);
should.equal(prevUrl, 'http://127.0.0.1:2369/test/page/3/');
});
it('should return null if no pagination prev', function () {
var prevUrl = getPreviousUrl({
relativeUrl: '/',
pagination: {
next: '2'
}
});
should.equal(prevUrl, null);
});
it('should return null if no relative url', function () {
var prevUrl = getPreviousUrl({
relativeUrl: '',
pagination: {
prev: '2'
}
});
should.equal(prevUrl, null);
});
});

View File

@ -0,0 +1,54 @@
/*globals describe, it*/
var getPublishedDate = require('../../../server/data/meta/published_date'),
should = require('should');
describe('getPublishedDate', function () {
it('should return published at date as ISO 8601 from context if exists', function () {
var pubDate = getPublishedDate({
context: ['post'],
post: {
published_at: new Date('2016-01-01 12:56:45.232Z')
}
});
should.equal(pubDate, '2016-01-01T12:56:45.232Z');
});
it('should return created at date as ISO 8601 if no published at date', function () {
var pubDate = getPublishedDate({
context: ['author'],
author: {
created_at: new Date('2016-01-01 12:56:45.232Z')
}
});
should.equal(pubDate, '2016-01-01T12:56:45.232Z');
});
it('should return published at over created at date as ISO 8601 if has both', function () {
var pubDate = getPublishedDate({
context: ['post'],
post: {
published_at: new Date('2016-01-01 12:56:45.232Z'),
created_at: new Date('2015-01-01 12:56:45.232Z')
}
});
should.equal(pubDate, '2016-01-01T12:56:45.232Z');
});
it('should return null if no update_at date on context', function () {
var pubDate = getPublishedDate({
context: ['author'],
author: {}
});
should.equal(pubDate, null);
});
it('should return null if context and property do not match in name', function () {
var pubDate = getPublishedDate({
context: ['author'],
post: {
published_at: new Date('2016-01-01 12:56:45.232Z')
}
});
should.equal(pubDate, null);
});
});

View File

@ -0,0 +1,26 @@
/*globals describe, it*/
var getRssUrl = require('../../../server/data/meta/rss_url'),
should = require('should');
describe('getRssUrl', function () {
it('should return rss url', function () {
var rssUrl = getRssUrl({
secure: false
});
should.equal(rssUrl, '/rss/');
});
it('should return absolute rss url', function () {
var rssUrl = getRssUrl({
secure: false
}, true);
should.equal(rssUrl, 'http://127.0.0.1:2369/rss/');
});
it('should return absolute rss url with https if secure', function () {
var rssUrl = getRssUrl({
secure: true
}, true);
should.equal(rssUrl, 'https://127.0.0.1:2369/rss/');
});
});

View File

@ -0,0 +1,177 @@
/*globals describe, it*/
var getSchema = require('../../../server/data/meta/schema'),
should = require('should');
describe('getSchema', function () {
it('should return post schema if context starts with post', function () {
var metadata = {
blog: {
title: 'Blog Title'
},
authorImage: 'http://mysite.com/author/image/url/me.jpg',
authorUrl: 'http://mysite.com/author/me/',
metaTitle: 'Post Title',
url: 'http://mysite.com/post/my-post-slug/',
publishedDate: '2015-12-25T05:35:01.234Z',
modifiedDate: '2016-01-21T22:13:05.412Z',
coverImage: 'http://mysite.com/content/image/mypostcoverimage.jpg',
keywords: ['one', 'two', 'tag'],
metaDescription: 'Post meta description'
}, data = {
context: ['post'],
post: {
author: {
name: 'Post Author',
website: 'http://myblogsite.com/',
bio: 'My author bio.'
}
}
}, schema = getSchema(metadata, data);
should.deepEqual(schema, {
'@context': 'http://schema.org',
'@type': 'Article',
author: {
'@type': 'Person',
description: 'My author bio.',
image: 'http://mysite.com/author/image/url/me.jpg',
name: 'Post Author',
sameAs: 'http://myblogsite.com/',
url: 'http://mysite.com/author/me/'
},
dateModified: '2016-01-21T22:13:05.412Z',
datePublished: '2015-12-25T05:35:01.234Z',
description: 'Post meta description',
headline: 'Post Title',
image: 'http://mysite.com/content/image/mypostcoverimage.jpg',
keywords: 'one, two, tag',
publisher: 'Blog Title',
url: 'http://mysite.com/post/my-post-slug/'
});
});
it('should return post schema removing null or undefined values', function () {
var metadata = {
blog: {
title: 'Blog Title'
},
authorImage: null,
authorUrl: 'http://mysite.com/author/me/',
metaTitle: 'Post Title',
url: 'http://mysite.com/post/my-post-slug/',
publishedDate: '2015-12-25T05:35:01.234Z',
modifiedDate: '2016-01-21T22:13:05.412Z',
coverImage: undefined,
keywords: [],
metaDescription: 'Post meta description'
}, data = {
context: ['post'],
post: {
author: {
name: 'Post Author',
website: undefined,
bio: null
}
}
}, schema = getSchema(metadata, data);
should.deepEqual(schema, {
'@context': 'http://schema.org',
'@type': 'Article',
author: {
'@type': 'Person',
name: 'Post Author',
url: 'http://mysite.com/author/me/'
},
dateModified: '2016-01-21T22:13:05.412Z',
datePublished: '2015-12-25T05:35:01.234Z',
description: 'Post meta description',
headline: 'Post Title',
publisher: 'Blog Title',
url: 'http://mysite.com/post/my-post-slug/'
});
});
it('should return home schema if context starts with home', function () {
var metadata = {
blog: {
title: 'Blog Title'
},
url: 'http://mysite.com/post/my-post-slug/',
coverImage: 'http://mysite.com/content/image/mypostcoverimage.jpg',
metaDescription: 'This is the theme description'
}, data = {
context: ['home']
}, schema = getSchema(metadata, data);
should.deepEqual(schema, {
'@context': 'http://schema.org',
'@type': 'Website',
description: 'This is the theme description',
image: 'http://mysite.com/content/image/mypostcoverimage.jpg',
publisher: 'Blog Title',
url: 'http://mysite.com/post/my-post-slug/'
});
});
it('should return tag schema if context starts with tag', function () {
var metadata = {
blog: {
title: 'Blog Title'
},
url: 'http://mysite.com/post/my-post-slug/',
coverImage: 'http://mysite.com/content/image/mypostcoverimage.jpg',
metaDescription: 'This is the tag description!'
}, data = {
context: ['tag'],
tag: {
name: 'Great Tag'
}
}, schema = getSchema(metadata, data);
should.deepEqual(schema, {
'@context': 'http://schema.org',
'@type': 'Series',
description: 'This is the tag description!',
image: 'http://mysite.com/content/image/mypostcoverimage.jpg',
name: 'Great Tag',
publisher: 'Blog Title',
url: 'http://mysite.com/post/my-post-slug/'
});
});
it('should return author schema if context starts with author', function () {
var metadata = {
blog: {
title: 'Blog Title'
},
authorImage: 'http://mysite.com/author/image/url/me.jpg',
authorUrl: 'http://mysite.com/author/me/',
metaDescription: 'This is the author description!'
}, data = {
context: ['author'],
author: {
name: 'Author Name',
website: 'http://myblogsite.com/'
}
}, schema = getSchema(metadata, data);
should.deepEqual(schema, {
'@context': 'http://schema.org',
'@type': 'Person',
description: 'This is the author description!',
name: 'Author Name',
publisher: 'Blog Title',
sameAs: 'http://myblogsite.com/',
url: 'http://mysite.com/author/me/'
});
});
it('should return null if not a supported type', function () {
var metadata = {},
data = {},
schema = getSchema(metadata, data);
should.deepEqual(schema, null);
});
});

View File

@ -0,0 +1,66 @@
/*globals describe, it*/
var getStructuredData = require('../../../server/data/meta/structured_data'),
should = require('should');
describe('getStructuredData', function () {
it('should return structored data from metadata', function () {
var metadata = {
blog: {
title: 'Blog Title'
},
ogType: 'article',
metaTitle: 'Post Title',
canonicalUrl: 'http://mysite.com/post/my-post-slug/',
publishedDate: '2015-12-25T05:35:01.234Z',
modifiedDate: '2016-01-21T22:13:05.412Z',
coverImage: 'http://mysite.com/content/image/mypostcoverimage.jpg',
keywords: ['one', 'two', 'tag'],
metaDescription: 'Post meta description'
}, structuredData = getStructuredData(metadata);
should.deepEqual(structuredData, {
'article:modified_time': '2016-01-21T22:13:05.412Z',
'article:published_time': '2015-12-25T05:35:01.234Z',
'article:tag': ['one', 'two', 'tag'],
'og:description': 'Post meta description',
'og:image': 'http://mysite.com/content/image/mypostcoverimage.jpg',
'og:site_name': 'Blog Title',
'og:title': 'Post Title',
'og:type': 'article',
'og:url': 'http://mysite.com/post/my-post-slug/',
'twitter:card': 'summary_large_image',
'twitter:description': 'Post meta description',
'twitter:image:src': 'http://mysite.com/content/image/mypostcoverimage.jpg',
'twitter:title': 'Post Title',
'twitter:url': 'http://mysite.com/post/my-post-slug/'
});
});
it('should return structored data from metadata with no nulls', function () {
var metadata = {
blog: {
title: 'Blog Title'
},
ogType: 'article',
metaTitle: 'Post Title',
canonicalUrl: 'http://mysite.com/post/my-post-slug/',
publishedDate: '2015-12-25T05:35:01.234Z',
modifiedDate: '2016-01-21T22:13:05.412Z',
coverImage: undefined,
keywords: null,
metaDescription: null
}, structuredData = getStructuredData(metadata);
should.deepEqual(structuredData, {
'article:modified_time': '2016-01-21T22:13:05.412Z',
'article:published_time': '2015-12-25T05:35:01.234Z',
'og:site_name': 'Blog Title',
'og:title': 'Post Title',
'og:type': 'article',
'og:url': 'http://mysite.com/post/my-post-slug/',
'twitter:card': 'summary',
'twitter:title': 'Post Title',
'twitter:url': 'http://mysite.com/post/my-post-slug/'
});
});
});

View File

@ -0,0 +1,144 @@
/*globals describe, it*/
var getTitle = require('../../../server/data/meta/title'),
config = require('../../../server/config');
describe('getTitle', function () {
it('should return meta_title if on data root', function () {
var title = getTitle({
meta_title: 'My test title'
});
title.should.equal('My test title');
});
it('should return blog title if on home', function () {
config.set({
theme: {
title: 'My blog title'
}
});
var title = getTitle({}, {context: 'home'});
title.should.equal('My blog title');
});
it('should return author name - blog title if on data author page', function () {
config.set({
theme: {
title: 'My blog title 2'
}
});
var title = getTitle({
author: {
name: 'Author Name'
}
}, {context: 'author'});
title.should.equal('Author Name - My blog title 2');
});
it('should return author page title if on data author page with more then one page', function () {
config.set({
theme: {
title: 'My blog title 2'
}
});
var title = getTitle({
author: {
name: 'Author Name'
}
}, {
context: 'author',
pagination: {
total: 40,
page: 3
}
});
title.should.equal('Author Name - Page 3 - My blog title 2');
});
it('should return tag name - blog title if on data tag page no meta_title', function () {
config.set({
theme: {
title: 'My blog title 3'
}
});
var title = getTitle({
tag: {
name: 'Tag Name'
}
}, {context: 'tag'});
title.should.equal('Tag Name - My blog title 3');
});
it('should return tag name - page - blog title if on data tag page no meta_title', function () {
config.set({
theme: {
title: 'My blog title 3'
}
});
var title = getTitle({
tag: {
name: 'Tag Name'
}
}, {
context: 'tag',
pagination: {
total: 40,
page: 39
}
});
title.should.equal('Tag Name - Page 39 - My blog title 3');
});
it('should return tag meta_title if in tag data', function () {
var title = getTitle({
tag: {
name: 'Tag Name',
meta_title: 'My Tag Meta Title!'
}
}, {context: 'tag'});
title.should.equal('My Tag Meta Title!');
});
it('should return post title if in post context', function () {
var title = getTitle({
post: {
title: 'My awesome post!'
}
}, {context: 'post'});
title.should.equal('My awesome post!');
});
it('should return post title if in page context', function () {
var title = getTitle({
post: {
title: 'My awesome page!'
}
}, {context: 'page'});
title.should.equal('My awesome page!');
});
it('should return post meta_title if in post data', function () {
var title = getTitle({
post: {
name: 'My awesome post!',
meta_title: 'My Tag Meta Title Post! '
}
}, {context: 'post'});
title.should.equal('My Tag Meta Title Post!');
});
it('should return blog title with page if unknown type', function () {
config.set({
theme: {
title: 'My blog title 4'
}
});
var title = getTitle({}, {
context: 'paged',
pagination: {
total: 40,
page: 35
}
});
title.should.equal('My blog title 4 - Page 35');
});
});

View File

@ -0,0 +1,99 @@
/*globals describe, it*/
var getUrl = require('../../../server/data/meta/url');
describe('getUrl', function () {
it('should return url for a post', function () {
var url = getUrl({
html: '<p>Welcome to my post.</p>',
markdown: 'Welcome to my post.',
title: 'Welcome Post',
slug: 'welcome-post',
url: '/post/welcome-post/'
});
url.should.equal('/post/welcome-post/');
});
it('should return absolute url for a post', function () {
var url = getUrl({
html: '<p>Welcome to my post.</p>',
markdown: 'Welcome to my post.',
title: 'Welcome Post',
slug: 'welcome-post',
url: '/post/welcome-post/'
}, true);
url.should.equal('http://127.0.0.1:2369/post/welcome-post/');
});
it('should return url for a tag', function () {
var url = getUrl({
name: 'Great',
slug: 'great',
description: 'My great tag',
parent: null
});
url.should.equal('/tag/great/');
});
it('should return secure absolute url for a tag', function () {
var url = getUrl({
name: 'Great',
slug: 'great',
description: 'My great tag',
parent: null,
secure: true
}, true);
url.should.equal('https://127.0.0.1:2369/tag/great/');
});
it('should return url for a author', function () {
var url = getUrl({
name: 'Author Name',
bio: 'I am fun bio!',
website: 'http://myoksite.com',
status: 'active',
location: 'London',
slug: 'author-name'
});
url.should.equal('/author/author-name/');
});
it('should return secure absolute url for a author', function () {
var url = getUrl({
name: 'Author Name',
bio: 'I am fun bio!',
website: 'http://myoksite.com',
status: 'active',
location: 'London',
slug: 'author-name',
secure: true
}, true);
url.should.equal('https://127.0.0.1:2369/author/author-name/');
});
it('should return url for a nav', function () {
var url = getUrl({
label: 'About Me',
url: '/about-me/',
slug: 'about-me',
current: true
});
url.should.equal('/about-me/');
});
it('should return absolute url for a nav', function () {
var url = getUrl({
label: 'About Me',
url: '/about-me/',
slug: 'about-me',
current: true
}, true);
url.should.equal('http://127.0.0.1:2369/about-me/');
});
it('should return url for a context object with relative url', function () {
var url = getUrl({
relativeUrl: '/my/relitive/url/'
});
url.should.equal('/my/relitive/url/');
});
});