mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-02 07:43:11 +03:00
Adds structured data to first index/tag/author page
Closes #4677 - Tests if page is first page or paginated - Adds relevant structured data to index/tag/author page - Does not add structured data on paginated pages - For author structured data, cover image overrides image - blog cover image is made absolute by image helper - Tests updated to use regular expressions and new tests
This commit is contained in:
parent
5263a75644
commit
3229508c54
@ -21,143 +21,295 @@ var hbs = require('express-hbs'),
|
||||
excerpt = require('./excerpt'),
|
||||
tagsHelper = require('./tags'),
|
||||
imageHelper = require('./image'),
|
||||
blog,
|
||||
ghost_head;
|
||||
|
||||
function getImage(ops, context, contextObject) {
|
||||
if (context === 'home' || context === 'author') {
|
||||
contextObject.image = contextObject.cover;
|
||||
}
|
||||
|
||||
ops.push(imageHelper.call(contextObject, {hash: {absolute: true}}));
|
||||
|
||||
if (context === 'post' && contextObject.author) {
|
||||
ops.push(imageHelper.call(contextObject.author, {hash: {absolute: true}}));
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
function getPaginationUrls(pagination, relativeUrl, secure, head) {
|
||||
var trimmedUrl, next, prev,
|
||||
trimmedUrlpattern = /.+(?=\/page\/\d*\/)/,
|
||||
tagOrAuthorPattern = /\/(tag)|(author)\//;
|
||||
|
||||
trimmedUrl = relativeUrl.match(trimmedUrlpattern);
|
||||
if (pagination.prev) {
|
||||
prev = (pagination.prev > 1 ? '/page/' + pagination.prev + '/' : '/');
|
||||
prev = (trimmedUrl) ? trimmedUrl + prev : prev;
|
||||
head.push('<link rel="prev" href="' +
|
||||
config.urlFor({relativeUrl: prev, secure: secure}, true) + '" />'
|
||||
);
|
||||
}
|
||||
if (pagination.next) {
|
||||
next = '/page/' + pagination.next + '/';
|
||||
if (trimmedUrl) {
|
||||
next = trimmedUrl + next;
|
||||
} else if (tagOrAuthorPattern.test(relativeUrl)) {
|
||||
next = relativeUrl.slice(0, -1) + next;
|
||||
}
|
||||
head.push('<link rel="next" href="' +
|
||||
config.urlFor({relativeUrl: next, secure: secure}, true) + '" />'
|
||||
);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
function addContextMetaData(context, data, metaData) {
|
||||
// escaped data
|
||||
metaData.metaTitle = hbs.handlebars.Utils.escapeExpression(metaData.metaTitle);
|
||||
metaData.metaDescription = metaData.metaDescription ? hbs.handlebars.Utils.escapeExpression(metaData.metaDescription) : null;
|
||||
|
||||
if (context === 'author') {
|
||||
metaData.authorUrl = hbs.handlebars.Utils.escapeExpression(blog.url + '/author/' + data.author.slug);
|
||||
metaData.ogType = 'profile';
|
||||
} else if (context === 'post') {
|
||||
metaData.publishedDate = moment(data.post.published_at).toISOString();
|
||||
metaData.modifiedDate = moment(data.post.updated_at).toISOString();
|
||||
metaData.authorUrl = hbs.handlebars.Utils.escapeExpression(blog.url + '/author/' + data.post.author.slug);
|
||||
metaData.ogType = 'article';
|
||||
}
|
||||
return metaData;
|
||||
}
|
||||
|
||||
function initMetaData(context, data, results) {
|
||||
var metaData = {
|
||||
url: results[0].value(),
|
||||
metaDescription: results[1].value() || null,
|
||||
metaTitle: results[2].value(),
|
||||
coverImage: results.length > 3 ? results[3].value() : null,
|
||||
authorImage: results.length > 4 ? results[4].value() : null,
|
||||
publishedDate: null,
|
||||
modifiedDate: null,
|
||||
tags: null,
|
||||
card: 'summary',
|
||||
authorUrl: null,
|
||||
ogType: 'website',
|
||||
keywords: null,
|
||||
blog: blog,
|
||||
title: blog.title
|
||||
};
|
||||
|
||||
if (!metaData.metaDescription) {
|
||||
if (context === 'post') {
|
||||
metaData.metaDescription = excerpt.call(data.post, {hash: {words: '40'}}).string + '...';
|
||||
} else if (context === 'tag') {
|
||||
metaData.metaDescription = data.tag.description ? data.tag.description : null;
|
||||
}
|
||||
}
|
||||
return addContextMetaData(context, data, metaData);
|
||||
}
|
||||
|
||||
function getStructuredData(metaData) {
|
||||
var structuredData;
|
||||
|
||||
if (metaData.coverImage) {
|
||||
metaData.card = 'summary_large_image';
|
||||
}
|
||||
|
||||
structuredData = {
|
||||
'og:site_name': metaData.title,
|
||||
'og:type': metaData.ogType,
|
||||
'og:title': metaData.metaTitle,
|
||||
'og:description': metaData.metaDescription,
|
||||
'og:url': metaData.url,
|
||||
'og:image': metaData.coverImage,
|
||||
'article:published_time': metaData.publishedDate,
|
||||
'article:modified_time': metaData.modifiedDate,
|
||||
'article:tag': metaData.tags,
|
||||
'twitter:card': metaData.card,
|
||||
'twitter:title': metaData.metaTitle,
|
||||
'twitter:description': metaData.metaDescription,
|
||||
'twitter:url': metaData.url,
|
||||
'twitter:image:src': metaData.coverImage
|
||||
};
|
||||
|
||||
return structuredData;
|
||||
}
|
||||
|
||||
// Creates the final schema object with values that are not null
|
||||
function trimSchema(schema) {
|
||||
var schemaObject = {};
|
||||
|
||||
_.each(schema, function (value, key) {
|
||||
if (value !== null && value !== undefined) {
|
||||
schemaObject[key] = value;
|
||||
}
|
||||
});
|
||||
return schemaObject;
|
||||
}
|
||||
|
||||
function getPostSchema(metaData, data) {
|
||||
var schema = {
|
||||
'@context': 'http://schema.org',
|
||||
'@type': 'Article',
|
||||
publisher: metaData.title,
|
||||
author: {
|
||||
'@type': 'Person',
|
||||
name: data.post.author.name,
|
||||
image: metaData.authorImage,
|
||||
url: metaData.authorUrl,
|
||||
sameAs: data.post.author.website || null,
|
||||
description: data.post.author.bio || null
|
||||
},
|
||||
headline: metaData.metaTitle,
|
||||
url: metaData.url,
|
||||
datePublished: metaData.publishedDate,
|
||||
dateModified: metaData.modifiedDate,
|
||||
image: metaData.coverImage,
|
||||
keywords: metaData.keywords,
|
||||
description: metaData.metaDescription
|
||||
};
|
||||
return trimSchema(schema);
|
||||
}
|
||||
|
||||
function getTagSchema(metaData, data) {
|
||||
var schema = {
|
||||
'@context': 'http://schema.org',
|
||||
'@type': 'Series',
|
||||
publisher: metaData.title,
|
||||
url: metaData.url,
|
||||
image: metaData.coverImage,
|
||||
name: data.tag.name,
|
||||
description: metaData.metaDescription
|
||||
};
|
||||
|
||||
return trimSchema(schema);
|
||||
}
|
||||
|
||||
function getAuthorSchema(metaData, data) {
|
||||
var schema = {
|
||||
'@context': 'http://schema.org',
|
||||
'@type': 'Person',
|
||||
sameAs: data.author.website || null,
|
||||
publisher: metaData.title,
|
||||
name: data.author.name,
|
||||
url: metaData.authorUrl,
|
||||
image: metaData.coverImage,
|
||||
description: metaData.metaDescription
|
||||
};
|
||||
|
||||
return trimSchema(schema);
|
||||
}
|
||||
|
||||
function getHomeSchema(metaData) {
|
||||
var schema = {
|
||||
'@context': 'http://schema.org',
|
||||
'@type': 'Website',
|
||||
publisher: metaData.title,
|
||||
url: metaData.url,
|
||||
image: metaData.coverImage,
|
||||
description: metaData.metaDescription
|
||||
};
|
||||
|
||||
return trimSchema(schema);
|
||||
}
|
||||
|
||||
function chooseSchema(metaData, context, data) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
function finaliseStructuredData(structuredData, tags, head) {
|
||||
var type;
|
||||
_.each(structuredData, function (content, property) {
|
||||
if (property === 'article:tag') {
|
||||
_.each(tags, function (tag) {
|
||||
if (tag !== '') {
|
||||
tag = hbs.handlebars.Utils.escapeExpression(tag.trim());
|
||||
head.push('<meta property="' + property + '" content="' + tag + '" />');
|
||||
}
|
||||
});
|
||||
head.push('');
|
||||
} else if (content !== null && content !== undefined) {
|
||||
type = property.substring(0, 7) === 'twitter' ? 'name' : 'property';
|
||||
head.push('<meta ' + type + '="' + property + '" content="' + content + '" />');
|
||||
}
|
||||
});
|
||||
return head;
|
||||
}
|
||||
|
||||
function finaliseSchema(schema, head) {
|
||||
head.push('<script type="application/ld+json">\n' + JSON.stringify(schema, null, ' ') +
|
||||
'\n </script>\n'
|
||||
);
|
||||
return head;
|
||||
}
|
||||
|
||||
ghost_head = function (options) {
|
||||
// create a shortcut for theme config
|
||||
blog = config.theme;
|
||||
|
||||
/*jshint unused:false*/
|
||||
var self = this,
|
||||
blog = config.theme,
|
||||
useStructuredData = !config.isPrivacyDisabled('useStructuredData'),
|
||||
head = [],
|
||||
majorMinor = /^(\d+\.)?(\d+)/,
|
||||
trimmedVersion = this.version,
|
||||
trimmedUrlpattern = /.+(?=\/page\/\d*\/)/,
|
||||
tagOrAuthorPattern = /\/(tag)|(author)\//,
|
||||
trimmedUrl, next, prev, tags,
|
||||
ops = [],
|
||||
structuredData,
|
||||
coverImage, authorImage, keywords,
|
||||
schema,
|
||||
title = hbs.handlebars.Utils.escapeExpression(blog.title);
|
||||
title = hbs.handlebars.Utils.escapeExpression(blog.title),
|
||||
context = self.context[0],
|
||||
contextObject = self[context] || blog;
|
||||
|
||||
trimmedVersion = trimmedVersion ? trimmedVersion.match(majorMinor)[0] : '?';
|
||||
|
||||
// Push Async calls to an array of promises
|
||||
ops.push(urlHelper.call(self, {hash: {absolute: true}}));
|
||||
ops.push(meta_description.call(self, options));
|
||||
ops.push(meta_title.call(self, options));
|
||||
if (self.post) {
|
||||
ops.push(imageHelper.call(self.post, {hash: {absolute:true}}));
|
||||
|
||||
if (self.post.author) {
|
||||
ops.push(imageHelper.call(self.post.author, {hash: {absolute:true}}));
|
||||
}
|
||||
}
|
||||
ops = getImage(ops, context, contextObject);
|
||||
|
||||
// Resolves promises then push pushes meta data into ghost_head
|
||||
return Promise.settle(ops).then(function (results) {
|
||||
var url = results[0].value(),
|
||||
metaDescription = results[1].value(),
|
||||
metaTitle = results[2].value(),
|
||||
coverImage = results.length > 3 ? results[3].value() : null,
|
||||
authorImage = results.length > 4 ? results[4].value() : null,
|
||||
publishedDate, modifiedDate,
|
||||
tags = tagsHelper.call(self.post, {hash: {autolink: 'false'}}).string.split(','),
|
||||
card = 'summary',
|
||||
type, authorUrl;
|
||||
var metaData = initMetaData(context, self, results),
|
||||
tags = tagsHelper.call(self.post, {hash: {autolink: 'false'}}).string.split(',');
|
||||
|
||||
if (!metaDescription) {
|
||||
metaDescription = excerpt.call(self.post, {hash: {words: '40'}}).string;
|
||||
}
|
||||
// If there are tags - build the keywords metaData string
|
||||
if (tags[0] !== '') {
|
||||
keywords = hbs.handlebars.Utils.escapeExpression(tagsHelper.call(self.post, {hash: {autolink: 'false', separator: ', '}}).string);
|
||||
metaData.keywords = hbs.handlebars.Utils.escapeExpression(tagsHelper.call(self.post,
|
||||
{hash: {autolink: 'false', separator: ', '}}
|
||||
).string);
|
||||
}
|
||||
head.push('<link rel="canonical" href="' + url + '" />');
|
||||
|
||||
// head is our main array that holds our meta data
|
||||
head.push('<link rel="canonical" href="' + metaData.url + '" />');
|
||||
|
||||
// Generate context driven pagination urls
|
||||
if (self.pagination) {
|
||||
trimmedUrl = self.relativeUrl.match(trimmedUrlpattern);
|
||||
if (self.pagination.prev) {
|
||||
prev = (self.pagination.prev > 1 ? prev = '/page/' + self.pagination.prev + '/' : prev = '/');
|
||||
prev = (trimmedUrl) ? trimmedUrl + prev : prev;
|
||||
head.push('<link rel="prev" href="' + config.urlFor({relativeUrl: prev, secure: self.secure}, true) + '" />');
|
||||
}
|
||||
if (self.pagination.next) {
|
||||
next = '/page/' + self.pagination.next + '/';
|
||||
if (trimmedUrl) {
|
||||
next = trimmedUrl + next;
|
||||
} else if (tagOrAuthorPattern.test(self.relativeUrl)) {
|
||||
next = self.relativeUrl.slice(0, -1) + next;
|
||||
}
|
||||
head.push('<link rel="next" href="' + config.urlFor({relativeUrl: next, secure: self.secure}, true) + '" />');
|
||||
}
|
||||
getPaginationUrls(self.pagination, self.relativeUrl, self.secure, head);
|
||||
}
|
||||
|
||||
// Test to see if we are on a post page and that Structured data has not been disabled in config.js
|
||||
if (self.post && useStructuredData) {
|
||||
publishedDate = moment(self.post.published_at).toISOString();
|
||||
modifiedDate = moment(self.post.updated_at).toISOString();
|
||||
|
||||
if (coverImage) {
|
||||
card = 'summary_large_image';
|
||||
}
|
||||
|
||||
// escaped data
|
||||
metaTitle = hbs.handlebars.Utils.escapeExpression(metaTitle);
|
||||
metaDescription = hbs.handlebars.Utils.escapeExpression(metaDescription + '...');
|
||||
authorUrl = hbs.handlebars.Utils.escapeExpression(blog.url + '/author/' + self.post.author.slug);
|
||||
|
||||
schema = {
|
||||
'@context': 'http://schema.org',
|
||||
'@type': 'Article',
|
||||
publisher: title,
|
||||
author: {
|
||||
'@type': 'Person',
|
||||
name: self.post.author.name,
|
||||
image: authorImage,
|
||||
url: authorUrl,
|
||||
sameAs: self.post.author.website
|
||||
},
|
||||
headline: metaTitle,
|
||||
url: url,
|
||||
datePublished: publishedDate,
|
||||
dateModified: modifiedDate,
|
||||
image: coverImage,
|
||||
keywords: keywords,
|
||||
description: metaDescription
|
||||
};
|
||||
|
||||
structuredData = {
|
||||
'og:site_name': title,
|
||||
'og:type': 'article',
|
||||
'og:title': metaTitle,
|
||||
'og:description': metaDescription,
|
||||
'og:url': url,
|
||||
'og:image': coverImage,
|
||||
'article:published_time': publishedDate,
|
||||
'article:modified_time': modifiedDate,
|
||||
'article:tag': tags,
|
||||
'twitter:card': card,
|
||||
'twitter:title': metaTitle,
|
||||
'twitter:description': metaDescription,
|
||||
'twitter:url': url,
|
||||
'twitter:image:src': coverImage
|
||||
};
|
||||
if (context !== 'paged' && context !== 'page' && useStructuredData) {
|
||||
// Create context driven OpenGraph and Twitter meta data
|
||||
structuredData = getStructuredData(metaData);
|
||||
// Create context driven JSONLD object
|
||||
schema = chooseSchema(metaData, context, self);
|
||||
head.push('');
|
||||
_.each(structuredData, function (content, property) {
|
||||
if (property === 'article:tag') {
|
||||
_.each(tags, function (tag) {
|
||||
if (tag !== '') {
|
||||
tag = hbs.handlebars.Utils.escapeExpression(tag.trim());
|
||||
head.push('<meta property="' + property + '" content="' + tag + '" />');
|
||||
}
|
||||
});
|
||||
head.push('');
|
||||
} else if (content !== null && content !== undefined) {
|
||||
type = property.substring(0, 7) === 'twitter' ? 'name' : 'property';
|
||||
head.push('<meta ' + type + '="' + property + '" content="' + content + '" />');
|
||||
}
|
||||
});
|
||||
// Formats structured data and pushes to head array
|
||||
finaliseStructuredData(structuredData, tags, head);
|
||||
head.push('');
|
||||
head.push('<script type="application/ld+json">\n' + JSON.stringify(schema, null, ' ') + '\n </script>\n');
|
||||
// Formats schema script/JSONLD data and pushes to head array
|
||||
finaliseSchema(schema, head);
|
||||
}
|
||||
|
||||
head.push('<meta name="generator" content="Ghost ' + trimmedVersion + '" />');
|
||||
|
@ -14,22 +14,26 @@ var should = require('should'),
|
||||
|
||||
describe('{{ghost_head}} helper', function () {
|
||||
var sandbox;
|
||||
|
||||
before(function () {
|
||||
utils.loadHelpers();
|
||||
utils.overrideConfig({
|
||||
url: 'http://testurl.com/',
|
||||
theme: {
|
||||
title: 'Ghost'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
utils.restoreConfig();
|
||||
});
|
||||
|
||||
describe('without Code Injection', function () {
|
||||
before(function () {
|
||||
utils.overrideConfig({
|
||||
url: 'http://testurl.com/',
|
||||
theme: {
|
||||
title: 'Ghost',
|
||||
description: 'blog description',
|
||||
cover: '/content/images/blog-cover.png'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
utils.restoreConfig();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.stub(api.settings, 'read', function () {
|
||||
@ -49,15 +53,241 @@ describe('{{ghost_head}} helper', function () {
|
||||
should.exist(handlebars.helpers.ghost_head);
|
||||
});
|
||||
|
||||
it('returns meta tag string', function (done) {
|
||||
it('returns meta tag string on paginated index page without structured data and schema', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', post: false},
|
||||
{data: {root: {context: []}}}
|
||||
{version: '0.3.0', relativeUrl: '/page/2/', context: ['paged', 'index']},
|
||||
{data: {root: {context: ['paged', 'index']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/" />\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/page\/2\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta property="og/);
|
||||
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('returns structured data on first index page', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/', context: ['home', 'index']},
|
||||
{data: {root: {context: ['home', 'index']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:title" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:description" content="blog description" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:url" content="http:\/\/testurl.com\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:image" content="http:\/\/testurl.com\/content\/images\/blog-cover.png" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:title" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:description" content="blog description" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/testurl.com\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:image:src" content="http:\/\/testurl.com\/content\/images\/blog-cover.png" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/"@type": "Website"/);
|
||||
rendered.string.should.match(/"publisher": "Ghost"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/"/);
|
||||
rendered.string.should.match(/"image": "http:\/\/testurl.com\/content\/images\/blog-cover.png"/);
|
||||
rendered.string.should.match(/"description": "blog description"/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('returns structured data and schema first tag page with meta description and meta title', function (done) {
|
||||
var tag = {
|
||||
meta_description: 'tag meta description',
|
||||
name: 'tagtitle',
|
||||
meta_title: 'tag meta title',
|
||||
image: '/content/images/tag-image.png'
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/tag/tagtitle/', tag: tag, context: ['tag']},
|
||||
{data: {root: {context: ['tag']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/tag\/tagtitle\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:title" content="tag meta title" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:description" content="tag meta description" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:url" content="http:\/\/testurl.com\/tag\/tagtitle\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:image" content="http:\/\/testurl.com\/content\/images\/tag-image.png" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:title" content="tag meta title" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:description" content="tag meta description" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/testurl.com\/tag\/tagtitle\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:image:src" content="http:\/\/testurl.com\/content\/images\/tag-image.png" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/"@type": "Series"/);
|
||||
rendered.string.should.match(/"publisher": "Ghost"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/tag\/tagtitle\/"/);
|
||||
rendered.string.should.match(/"image": "http:\/\/testurl.com\/content\/images\/tag-image.png"/);
|
||||
rendered.string.should.match(/"name": "tagtitle"/);
|
||||
rendered.string.should.match(/"description": "tag meta description"/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('tag first page without meta description uses tag description, and title if no meta title', function (done) {
|
||||
var tag = {
|
||||
meta_description: '',
|
||||
description: 'tag description',
|
||||
name: 'tagtitle',
|
||||
meta_title: '',
|
||||
image: '/content/images/tag-image.png'
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/tag/tagtitle/', tag: tag, context: ['tag']},
|
||||
{data: {root: {context: ['tag']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/tag\/tagtitle\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:type" content="website" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:title" content="tagtitle - Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:description" content="tag description" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:url" content="http:\/\/testurl.com\/tag\/tagtitle\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:image" content="http:\/\/testurl.com\/content\/images\/tag-image.png" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:title" content="tagtitle - Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:description" content="tag description" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/testurl.com\/tag\/tagtitle\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:image:src" content="http:\/\/testurl.com\/content\/images\/tag-image.png" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/"@type": "Series"/);
|
||||
rendered.string.should.match(/"publisher": "Ghost"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/tag\/tagtitle\/"/);
|
||||
rendered.string.should.match(/"image": "http:\/\/testurl.com\/content\/images\/tag-image.png"/);
|
||||
rendered.string.should.match(/"name": "tagtitle"/);
|
||||
rendered.string.should.match(/"description": "tag description"/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('tag first page with meta and model description returns no description fields', function (done) {
|
||||
var tag = {
|
||||
meta_description: '',
|
||||
name: 'tagtitle',
|
||||
meta_title: '',
|
||||
image: '/content/images/tag-image.png'
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/tag/tagtitle/', tag: tag, context: ['tag']},
|
||||
{data: {root: {context: ['tag']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.not.match(/<meta property="og:description" \/>/);
|
||||
rendered.string.should.not.match(/<meta name="twitter:description"\/>/);
|
||||
rendered.string.should.not.match(/"description":/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not return structured data on paginated tag pages', function (done) {
|
||||
var tag = {
|
||||
meta_description: 'tag meta description',
|
||||
title: 'tagtitle',
|
||||
meta_title: 'tag meta title',
|
||||
image: '/content/images/tag-image.png'
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/tag/tagtitle/page/2/', tag: tag, context: ['paged', 'tag']},
|
||||
{data: {root: {context: ['tag']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/tag\/tagtitle\/page\/2\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta property="og/);
|
||||
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('returns structured data and schema on first author page with cover image', function (done) {
|
||||
var author = {
|
||||
name: 'Author name',
|
||||
slug: 'AuthorName',
|
||||
bio: 'Author bio',
|
||||
image: '/content/images/test-author-image.png',
|
||||
cover: '/content/images/author-cover-image.png',
|
||||
website: 'http://authorwebsite.com'
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/author/AuthorName/', author: author, context: ['author']},
|
||||
{data: {root: {context: ['author']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/author\/AuthorName\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:type" content="profile" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:description" content="Author bio" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:url" content="http:\/\/testurl.com\/author\/AuthorName\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:image" content="http:\/\/testurl.com\/content\/images\/author-cover-image.png" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:title" content="Author name - Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:description" content="Author bio" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/testurl.com\/author\/AuthorName\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:image:src" content="http:\/\/testurl.com\/content\/images\/author-cover-image.png" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/"@type": "Person"/);
|
||||
rendered.string.should.match(/"sameAs": "http:\/\/authorwebsite.com"/);
|
||||
rendered.string.should.match(/"publisher": "Ghost"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/author\/AuthorName"/);
|
||||
rendered.string.should.match(/"image": "http:\/\/testurl.com\/content\/images\/author-cover-image.png"/);
|
||||
rendered.string.should.match(/"name": "Author name"/);
|
||||
rendered.string.should.match(/"description": "Author bio"/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not return structured data on paginated author pages', function (done) {
|
||||
var author = {
|
||||
name: 'Author name',
|
||||
slug: 'AuthorName',
|
||||
bio: 'Author bio',
|
||||
image: '/content/images/test-author-image.png',
|
||||
cover: '/content/images/author-cover-image.png',
|
||||
website: 'http://authorwebsite.com'
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/author/AuthorName/page/2/', author: author, context: ['paged', 'author']},
|
||||
{data: {root: {context: ['paged', 'author']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/author\/AuthorName\/page\/2\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta property="og/);
|
||||
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
@ -65,13 +295,13 @@ describe('{{ghost_head}} helper', function () {
|
||||
|
||||
it('returns meta tag string even if version is invalid', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.9'},
|
||||
{version: '0.9', context: []},
|
||||
{data: {root: {context: []}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/" />\n' +
|
||||
' <meta name="generator" content="Ghost 0.9" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.9" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
@ -90,43 +320,60 @@ describe('{{ghost_head}} helper', function () {
|
||||
url: 'http//:testauthorurl.com',
|
||||
slug: 'Author',
|
||||
image: '/content/images/test-author-image.png',
|
||||
website: 'http://authorwebsite.com'
|
||||
website: 'http://authorwebsite.com',
|
||||
bio: 'Author bio'
|
||||
}
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{relativeUrl: '/post/', version: '0.3.0', post: post},
|
||||
{relativeUrl: '/post/', version: '0.3.0', context: ['post'], post: post},
|
||||
{data: {root: {context: ['post']}}}
|
||||
).then(function (rendered) {
|
||||
var re1 = new RegExp('<meta property="article:published_time" content="' + post.published_at),
|
||||
re2 = new RegExp('<meta property="article:modified_time" content="' + post.updated_at),
|
||||
re3 = new RegExp('"datePublished": "' + post.published_at),
|
||||
re4 = new RegExp('"dateModified": "' + post.updated_at);
|
||||
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/post/" />\n \n' +
|
||||
' <meta property="og:site_name" content="Ghost" />\n' +
|
||||
' <meta property="og:type" content="article" />\n' +
|
||||
' <meta property="og:title" content="Welcome to Ghost" />\n' +
|
||||
' <meta property="og:description" content="blog description..." />\n' +
|
||||
' <meta property="og:url" content="http://testurl.com/post/" />\n' +
|
||||
' <meta property="og:image" content="http://testurl.com/content/images/test-image.png" />\n' +
|
||||
' <meta property="article:published_time" content="' + post.published_at + '" />\n' +
|
||||
' <meta property="article:modified_time" content="' + post.updated_at + '" />\n' +
|
||||
' <meta property="article:tag" content="tag1" />\n' +
|
||||
' <meta property="article:tag" content="tag2" />\n' +
|
||||
' <meta property="article:tag" content="tag3" />\n \n' +
|
||||
' <meta name="twitter:card" content="summary_large_image" />\n' +
|
||||
' <meta name="twitter:title" content="Welcome to Ghost" />\n' +
|
||||
' <meta name="twitter:description" content="blog description..." />\n' +
|
||||
' <meta name="twitter:url" content="http://testurl.com/post/" />\n' +
|
||||
' <meta name="twitter:image:src" content="http://testurl.com/content/images/test-image.png" />\n \n' +
|
||||
' <script type=\"application/ld+json\">\n{\n' +
|
||||
' "@context": "http://schema.org",\n "@type": "Article",\n "publisher": "Ghost",\n' +
|
||||
' "author": {\n "@type": "Person",\n "name": "Author name",\n ' +
|
||||
' \"image\": \"http://testurl.com/content/images/test-author-image.png\",\n ' +
|
||||
' "url": "http://testurl.com/author/Author",\n "sameAs": "http://authorwebsite.com"\n ' +
|
||||
'},\n "headline": "Welcome to Ghost",\n "url": "http://testurl.com/post/",\n' +
|
||||
' "datePublished": "' + post.published_at + '",\n "dateModified": "' + post.updated_at + '",\n' +
|
||||
' "image": "http://testurl.com/content/images/test-image.png",\n "keywords": "tag1, tag2, tag3",\n' +
|
||||
' "description": "blog description..."\n}\n </script>\n\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:description" content="blog description" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:url" content="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:image" content="http:\/\/testurl.com\/content\/images\/test-image.png" \/>/);
|
||||
rendered.string.should.match(re1);
|
||||
rendered.string.should.match(re2);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag1" \/>/);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag2" \/>/);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag3" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:description" content="blog description" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:image:src" content="http:\/\/testurl.com\/content\/images\/test-image.png" \/>/);
|
||||
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/"@type": "Article"/);
|
||||
rendered.string.should.match(/"publisher": "Ghost"/);
|
||||
rendered.string.should.match(/"author": {/);
|
||||
rendered.string.should.match(/"@type": "Person"/);
|
||||
rendered.string.should.match(/"name": "Author name"/);
|
||||
rendered.string.should.match(/"image\": \"http:\/\/testurl.com\/content\/images\/test-author-image.png\"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/author\/Author"/);
|
||||
rendered.string.should.match(/"sameAs": "http:\/\/authorwebsite.com"/);
|
||||
rendered.string.should.match(/"description": "Author bio"/);
|
||||
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/post\/"/);
|
||||
rendered.string.should.match(re3);
|
||||
rendered.string.should.match(re4);
|
||||
rendered.string.should.match(/"image": "http:\/\/testurl.com\/content\/images\/test-image.png"/);
|
||||
rendered.string.should.match(/"keywords": "tag1, tag2, tag3"/);
|
||||
rendered.string.should.match(/"description": "blog description"/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
@ -151,38 +398,54 @@ describe('{{ghost_head}} helper', function () {
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{relativeUrl: '/post/', version: '0.3.0', post: post},
|
||||
{relativeUrl: '/post/', version: '0.3.0', context: ['post'], post: post},
|
||||
{data: {root: {context: ['post']}}}
|
||||
).then(function (rendered) {
|
||||
var re1 = new RegExp('<meta property="article:published_time" content="' + post.published_at),
|
||||
re2 = new RegExp('<meta property="article:modified_time" content="' + post.updated_at),
|
||||
re3 = new RegExp('"datePublished": "' + post.published_at),
|
||||
re4 = new RegExp('"dateModified": "' + post.updated_at);
|
||||
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/post/" />\n \n' +
|
||||
' <meta property="og:site_name" content="Ghost" />\n' +
|
||||
' <meta property="og:type" content="article" />\n' +
|
||||
' <meta property="og:title" content="Welcome to Ghost "test"" />\n' +
|
||||
' <meta property="og:description" content="blog "test" description..." />\n' +
|
||||
' <meta property="og:url" content="http://testurl.com/post/" />\n' +
|
||||
' <meta property="og:image" content="http://testurl.com/content/images/test-image.png" />\n' +
|
||||
' <meta property="article:published_time" content="' + post.published_at + '" />\n' +
|
||||
' <meta property="article:modified_time" content="' + post.updated_at + '" />\n' +
|
||||
' <meta property="article:tag" content="tag1" />\n' +
|
||||
' <meta property="article:tag" content="tag2" />\n' +
|
||||
' <meta property="article:tag" content="tag3" />\n \n' +
|
||||
' <meta name="twitter:card" content="summary_large_image" />\n' +
|
||||
' <meta name="twitter:title" content="Welcome to Ghost "test"" />\n' +
|
||||
' <meta name="twitter:description" content="blog "test" description..." />\n' +
|
||||
' <meta name="twitter:url" content="http://testurl.com/post/" />\n' +
|
||||
' <meta name="twitter:image:src" content="http://testurl.com/content/images/test-image.png" />\n \n' +
|
||||
' <script type=\"application/ld+json\">\n{\n' +
|
||||
' "@context": "http://schema.org",\n "@type": "Article",\n "publisher": "Ghost",\n' +
|
||||
' "author": {\n "@type": "Person",\n "name": "Author name",\n ' +
|
||||
' \"image\": \"http://testurl.com/content/images/test-author-image.png\",\n ' +
|
||||
' "url": "http://testurl.com/author/Author",\n "sameAs": "http://authorwebsite.com"\n ' +
|
||||
'},\n "headline": "Welcome to Ghost "test"",\n "url": "http://testurl.com/post/",\n' +
|
||||
' "datePublished": "' + post.published_at + '",\n "dateModified": "' + post.updated_at + '",\n' +
|
||||
' "image": "http://testurl.com/content/images/test-image.png",\n "keywords": "tag1, tag2, tag3",\n' +
|
||||
' "description": "blog "test" description..."\n}\n </script>\n\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost "test"" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:description" content="blog "test" description" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:url" content="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:image" content="http:\/\/testurl.com\/content\/images\/test-image.png" \/>/);
|
||||
rendered.string.should.match(re1);
|
||||
rendered.string.should.match(re2);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag1" \/>/);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag2" \/>/);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag3" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost "test"" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:description" content="blog "test" description" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:image:src" content="http:\/\/testurl.com\/content\/images\/test-image.png" \/>/);
|
||||
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/"@type": "Article"/);
|
||||
rendered.string.should.match(/"publisher": "Ghost"/);
|
||||
rendered.string.should.match(/"author": {/);
|
||||
rendered.string.should.match(/"@type": "Person"/);
|
||||
rendered.string.should.match(/"name": "Author name"/);
|
||||
rendered.string.should.match(/"image\": \"http:\/\/testurl.com\/content\/images\/test-author-image.png\"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/author\/Author"/);
|
||||
rendered.string.should.match(/"sameAs": "http:\/\/authorwebsite.com"/);
|
||||
rendered.string.should.match(/"headline": "Welcome to Ghost "test""/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/post\/"/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(re3);
|
||||
rendered.string.should.match(re4);
|
||||
rendered.string.should.match(/"image": "http:\/\/testurl.com\/content\/images\/test-image.png"/);
|
||||
rendered.string.should.match(/"keywords": "tag1, tag2, tag3"/);
|
||||
rendered.string.should.match(/"description": "blog "test" description"/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
@ -206,35 +469,51 @@ describe('{{ghost_head}} helper', function () {
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{relativeUrl: '/post/', version: '0.3.0', post: post},
|
||||
{data: {root: {context: ['post']}}}
|
||||
).then(function (rendered) {
|
||||
{relativeUrl: '/post/', version: '0.3.0', context: ['post'], post: post},
|
||||
{data: {root: {context: ['post']}}}).then(function (rendered) {
|
||||
var re1 = new RegExp('<meta property="article:published_time" content="' + post.published_at),
|
||||
re2 = new RegExp('<meta property="article:modified_time" content="' + post.updated_at),
|
||||
re3 = new RegExp('"datePublished": "' + post.published_at),
|
||||
re4 = new RegExp('"dateModified": "' + post.updated_at);
|
||||
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/post/" />\n \n' +
|
||||
' <meta property="og:site_name" content="Ghost" />\n' +
|
||||
' <meta property="og:type" content="article" />\n' +
|
||||
' <meta property="og:title" content="Welcome to Ghost" />\n' +
|
||||
' <meta property="og:description" content="blog description..." />\n' +
|
||||
' <meta property="og:url" content="http://testurl.com/post/" />\n' +
|
||||
' <meta property="og:image" content="http://testurl.com/content/images/test-image.png" />\n' +
|
||||
' <meta property="article:published_time" content="' + post.published_at + '" />\n' +
|
||||
' <meta property="article:modified_time" content="' + post.updated_at + '" />\n \n' +
|
||||
' <meta name="twitter:card" content="summary_large_image" />\n' +
|
||||
' <meta name="twitter:title" content="Welcome to Ghost" />\n' +
|
||||
' <meta name="twitter:description" content="blog description..." />\n' +
|
||||
' <meta name="twitter:url" content="http://testurl.com/post/" />\n' +
|
||||
' <meta name="twitter:image:src" content="http://testurl.com/content/images/test-image.png" />\n \n' +
|
||||
' <script type=\"application/ld+json\">\n{\n' +
|
||||
' "@context": "http://schema.org",\n "@type": "Article",\n "publisher": "Ghost",\n' +
|
||||
' "author": {\n "@type": "Person",\n "name": "Author name",\n ' +
|
||||
' \"image\": \"http://testurl.com/content/images/test-author-image.png\",\n ' +
|
||||
' "url": "http://testurl.com/author/Author",\n "sameAs": "http://authorwebsite.com"\n ' +
|
||||
'},\n "headline": "Welcome to Ghost",\n "url": "http://testurl.com/post/",\n' +
|
||||
' "datePublished": "' + post.published_at + '",\n "dateModified": "' + post.updated_at + '",\n' +
|
||||
' "image": "http://testurl.com/content/images/test-image.png",\n' +
|
||||
' "description": "blog description..."\n}\n </script>\n\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:description" content="blog description" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:url" content="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:image" content="http:\/\/testurl.com\/content\/images\/test-image.png" \/>/);
|
||||
rendered.string.should.match(re1);
|
||||
rendered.string.should.match(re2);
|
||||
rendered.string.should.not.match(/<meta property="article:tag"/);
|
||||
rendered.string.should.match(/<meta name="twitter:card" content="summary_large_image" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:description" content="blog description" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:image:src" content="http:\/\/testurl.com\/content\/images\/test-image.png" \/>/);
|
||||
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/"@type": "Article"/);
|
||||
rendered.string.should.match(/"publisher": "Ghost"/);
|
||||
rendered.string.should.match(/"author": {/);
|
||||
rendered.string.should.match(/"@type": "Person"/);
|
||||
rendered.string.should.match(/"name": "Author name"/);
|
||||
rendered.string.should.match(/"image\": \"http:\/\/testurl.com\/content\/images\/test-author-image.png\"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/author\/Author"/);
|
||||
rendered.string.should.match(/"sameAs": "http:\/\/authorwebsite.com"/);
|
||||
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/post\/"/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(re3);
|
||||
rendered.string.should.match(re4);
|
||||
rendered.string.should.match(/"image": "http:\/\/testurl.com\/content\/images\/test-image.png"/);
|
||||
rendered.string.should.not.match(/"keywords":/);
|
||||
rendered.string.should.match(/"description": "blog description"/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
@ -258,46 +537,169 @@ describe('{{ghost_head}} helper', function () {
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{relativeUrl: '/post/', version: '0.3.0', post: post},
|
||||
{relativeUrl: '/post/', version: '0.3.0', context: ['post'], post: post},
|
||||
{data: {root: {context: ['post']}}}
|
||||
).then(function (rendered) {
|
||||
var re1 = new RegExp('<meta property="article:published_time" content="' + post.published_at),
|
||||
re2 = new RegExp('<meta property="article:modified_time" content="' + post.updated_at),
|
||||
re3 = new RegExp('"datePublished": "' + post.published_at),
|
||||
re4 = new RegExp('"dateModified": "' + post.updated_at);
|
||||
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/post/" />\n \n' +
|
||||
' <meta property="og:site_name" content="Ghost" />\n' +
|
||||
' <meta property="og:type" content="article" />\n' +
|
||||
' <meta property="og:title" content="Welcome to Ghost" />\n' +
|
||||
' <meta property="og:description" content="blog description..." />\n' +
|
||||
' <meta property="og:url" content="http://testurl.com/post/" />\n' +
|
||||
' <meta property="article:published_time" content="' + post.published_at + '" />\n' +
|
||||
' <meta property="article:modified_time" content="' + post.updated_at + '" />\n' +
|
||||
' <meta property="article:tag" content="tag1" />\n' +
|
||||
' <meta property="article:tag" content="tag2" />\n' +
|
||||
' <meta property="article:tag" content="tag3" />\n \n' +
|
||||
' <meta name="twitter:card" content="summary" />\n' +
|
||||
' <meta name="twitter:title" content="Welcome to Ghost" />\n' +
|
||||
' <meta name="twitter:description" content="blog description..." />\n' +
|
||||
' <meta name="twitter:url" content="http://testurl.com/post/" />\n \n' +
|
||||
' <script type=\"application/ld+json\">\n{\n' +
|
||||
' "@context": "http://schema.org",\n "@type": "Article",\n "publisher": "Ghost",\n' +
|
||||
' "author": {\n "@type": "Person",\n "name": "Author name",\n ' +
|
||||
' "url": "http://testurl.com/author/Author",\n "sameAs": "http://authorwebsite.com"\n ' +
|
||||
'},\n "headline": "Welcome to Ghost",\n "url": "http://testurl.com/post/",\n' +
|
||||
' "datePublished": "' + post.published_at + '",\n "dateModified": "' + post.updated_at + '",\n' +
|
||||
' "keywords": "tag1, tag2, tag3",\n "description": "blog description..."\n}\n </script>\n\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:site_name" content="Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:type" content="article" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:title" content="Welcome to Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:description" content="blog description" \/>/);
|
||||
rendered.string.should.match(/<meta property="og:url" content="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta property="og:image"/);
|
||||
rendered.string.should.match(re1);
|
||||
rendered.string.should.match(re2);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag1" \/>/);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag2" \/>/);
|
||||
rendered.string.should.match(/<meta property="article:tag" content="tag3" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:card" content="summary" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:title" content="Welcome to Ghost" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:description" content="blog description" \/>/);
|
||||
rendered.string.should.match(/<meta name="twitter:url" content="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta name="twitter:image:src"/);
|
||||
rendered.string.should.match(/<script type=\"application\/ld\+json\">/);
|
||||
rendered.string.should.match(/"@context": "http:\/\/schema.org"/);
|
||||
rendered.string.should.match(/"@type": "Article"/);
|
||||
rendered.string.should.match(/"publisher": "Ghost"/);
|
||||
rendered.string.should.match(/"author": {/);
|
||||
rendered.string.should.match(/"@type": "Person"/);
|
||||
rendered.string.should.match(/"name": "Author name"/);
|
||||
rendered.string.should.not.match(/"image\"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/author\/Author"/);
|
||||
rendered.string.should.match(/"sameAs": "http:\/\/authorwebsite.com"/);
|
||||
rendered.string.should.match(/"headline": "Welcome to Ghost"/);
|
||||
rendered.string.should.match(/"url": "http:\/\/testurl.com\/post\/"/);
|
||||
rendered.string.should.match(re3);
|
||||
rendered.string.should.match(re4);
|
||||
rendered.string.should.match(/"keywords": "tag1, tag2, tag3"/);
|
||||
rendered.string.should.match(/"description": "blog description"/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('does not return structured data if useStructuredData is set to false in config file', function (done) {
|
||||
it('returns canonical URL', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/about/', context: ['page']},
|
||||
{data: {root: {context: ['page']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/about\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta property="og/);
|
||||
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('returns next & prev URL correctly for middle page', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/page/3/', context: ['paged', 'index'], pagination: {next: '4', prev: '2'}},
|
||||
{data: {root: {context: ['index', 'paged'], pagination: {total: 4, page: 3, next: 4, prev: 2}}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/page\/3\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="prev" href="http:\/\/testurl.com\/page\/2\/" \/>/);
|
||||
rendered.string.should.match(/<link rel="next" href="http:\/\/testurl.com\/page\/4\/" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta property="og/);
|
||||
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('returns next & prev URL correctly for second page', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/page/2/', context: ['paged', 'index'], pagination: {next: '3', prev: '1'}},
|
||||
{data: {root: {context: ['index', 'paged'], pagination: {total: 3, page: 2, next: 3, prev: 1}}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/page\/2\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="prev" href="http:\/\/testurl.com\/" \/>/);
|
||||
rendered.string.should.match(/<link rel="next" href="http:\/\/testurl.com\/page\/3\/" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta property="og/);
|
||||
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
describe('with /blog subdirectory', function () {
|
||||
before(function () {
|
||||
utils.overrideConfig({
|
||||
url: 'http://testurl.com/blog/',
|
||||
theme: {
|
||||
title: 'Ghost',
|
||||
description: 'blog description',
|
||||
cover: '/content/images/blog-cover.png'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
utils.restoreConfig();
|
||||
});
|
||||
|
||||
it('returns correct rss url with subdirectory', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', context: ['paged', 'index']},
|
||||
{data: {root: {context: []}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/blog\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/blog\/rss\/" \/>/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with useStructuredData is set to false in config file', function () {
|
||||
before(function () {
|
||||
utils.overrideConfig({
|
||||
url: 'http://testurl.com/',
|
||||
theme: {
|
||||
title: 'Ghost',
|
||||
description: 'blog description',
|
||||
cover: '/content/images/blog-cover.png'
|
||||
},
|
||||
privacy: {
|
||||
useStructuredData: false
|
||||
}
|
||||
});
|
||||
sandbox = sinon.sandbox.create();
|
||||
sandbox.stub(api.settings, 'read', function () {
|
||||
return Promise.resolve({
|
||||
settings: [
|
||||
{value: ''}
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
utils.restoreConfig();
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('does not return structured data', function (done) {
|
||||
var post = {
|
||||
meta_description: 'blog description',
|
||||
title: 'Welcome to Ghost',
|
||||
@ -315,91 +717,19 @@ describe('{{ghost_head}} helper', function () {
|
||||
};
|
||||
|
||||
helpers.ghost_head.call(
|
||||
{relativeUrl: '/post/', version: '0.3.0', post: post},
|
||||
{relativeUrl: '/post/', version: '0.3.0', context: ['post'], post: post},
|
||||
{data: {root: {context: ['post']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/post/" />\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/post\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.not.match(/<meta property="og/);
|
||||
rendered.string.should.not.match(/<script type=\"application\/ld\+json\">/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('returns canonical URL', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/about/'},
|
||||
{data: {root: {context: ['page']}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/about/" />\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('returns next & prev URL correctly for middle page', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/page/3/', pagination: {next: '4', prev: '2'}},
|
||||
{data: {root: {context: ['index', 'paged'], pagination: {total: 4, page: 3, next: 4, prev: 2}}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/page/3/" />\n' +
|
||||
' <link rel="prev" href="http://testurl.com/page/2/" />\n' +
|
||||
' <link rel="next" href="http://testurl.com/page/4/" />\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('returns next & prev URL correctly for second page', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', relativeUrl: '/page/2/', pagination: {next: '3', prev: '1'}},
|
||||
{data: {root: {context: ['index', 'paged'], pagination: {total: 3, page: 2, next: 3, prev: 1}}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/page/2/" />\n' +
|
||||
' <link rel="prev" href="http://testurl.com/" />\n' +
|
||||
' <link rel="next" href="http://testurl.com/page/3/" />\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />');
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
describe('with /blog subdirectory', function () {
|
||||
before(function () {
|
||||
utils.overrideConfig({
|
||||
url: 'http://testurl.com/blog/',
|
||||
theme: {
|
||||
title: 'Ghost'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
utils.restoreConfig();
|
||||
});
|
||||
|
||||
it('returns correct rss url with subdirectory', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0'},
|
||||
{data: {root: {context: []}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/blog/" />\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" ' +
|
||||
'href="http://testurl.com/blog/rss/" />');
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with Code Injection', function () {
|
||||
@ -410,10 +740,13 @@ describe('{{ghost_head}} helper', function () {
|
||||
settings: [{value: '<style>body {background: red;}</style>'}]
|
||||
});
|
||||
});
|
||||
|
||||
utils.overrideConfig({
|
||||
url: 'http://testurl.com/',
|
||||
theme: {
|
||||
title: 'Ghost'
|
||||
title: 'Ghost',
|
||||
description: 'blog description',
|
||||
cover: '/content/images/blog-cover.png'
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -425,14 +758,14 @@ describe('{{ghost_head}} helper', function () {
|
||||
|
||||
it('returns meta tag plus injected code', function (done) {
|
||||
helpers.ghost_head.call(
|
||||
{version: '0.3.0', post: false},
|
||||
{version: '0.3.0', context: ['paged', 'index'], post: false},
|
||||
{data: {root: {context: []}}}
|
||||
).then(function (rendered) {
|
||||
should.exist(rendered);
|
||||
rendered.string.should.equal('<link rel="canonical" href="http://testurl.com/" />\n' +
|
||||
' <meta name="generator" content="Ghost 0.3" />\n' +
|
||||
' <link rel="alternate" type="application/rss+xml" title="Ghost" href="http://testurl.com/rss/" />\n' +
|
||||
' <style>body {background: red;}</style>');
|
||||
rendered.string.should.match(/<link rel="canonical" href="http:\/\/testurl.com\/" \/>/);
|
||||
rendered.string.should.match(/<meta name="generator" content="Ghost 0.3" \/>/);
|
||||
rendered.string.should.match(/<link rel="alternate" type="application\/rss\+xml" title="Ghost" href="http:\/\/testurl.com\/rss\/" \/>/);
|
||||
rendered.string.should.match(/<style>body {background: red;}<\/style>/);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
|
Loading…
Reference in New Issue
Block a user