mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Use urlJoin in RSS + test coverage
refs #1833 - move RSS tests to be in rss_spec.js - improve RSS test coverage - fix a bug with RSS title generation for tag RSS feeds - replace custom code in processUrls with urlJoin
This commit is contained in:
parent
2e9932b8eb
commit
34b22eefa2
5 changed files with 506 additions and 245 deletions
|
@ -49,8 +49,9 @@ function getData(options) {
|
|||
};
|
||||
|
||||
return Promise.props(ops).then(function (result) {
|
||||
var titleStart = options.tags ? result.results.meta.filters.tags[0].name + ' - ' :
|
||||
options.author ? result.results.meta.filters.author.name + ' - ' : '';
|
||||
var titleStart = '';
|
||||
if (options.tag) { titleStart = result.results.meta.filters.tags[0].name + ' - ' || ''; }
|
||||
if (options.author) { titleStart = result.results.meta.filters.author.name + ' - ' || ''; }
|
||||
|
||||
return {
|
||||
title: titleStart + result.title.settings[0].value,
|
||||
|
@ -104,18 +105,7 @@ function processUrls(html, siteUrl, itemUrl) {
|
|||
// if the relative URL begins with a '/' use the blog URL (including sub-directory)
|
||||
// as the base URL, otherwise use the post's URL.
|
||||
baseUrl = attributeValue[0] === '/' ? siteUrl : itemUrl;
|
||||
|
||||
// prevent double subdirectories
|
||||
if (attributeValue.indexOf(config.paths.subdir) === 0) {
|
||||
attributeValue = attributeValue.replace(config.paths.subdir, '');
|
||||
}
|
||||
|
||||
// prevent double slashes
|
||||
if (baseUrl.slice(-1) === '/' && attributeValue[0] === '/') {
|
||||
attributeValue = attributeValue.substr(1);
|
||||
}
|
||||
|
||||
attributeValue = baseUrl + attributeValue;
|
||||
attributeValue = config.urlJoin(baseUrl, attributeValue);
|
||||
el.attr(attributeName, attributeValue);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -397,6 +397,11 @@ describe('Frontend Routing', function () {
|
|||
});
|
||||
|
||||
describe('RSS', function () {
|
||||
/**
|
||||
* These tests are here to cover the headers sent with requests
|
||||
* and high-level redirects that can't be tested with the unit
|
||||
* tests in unit/rss_spec.js
|
||||
*/
|
||||
before(function (done) {
|
||||
testUtils.initData().then(function () {
|
||||
return testUtils.fixtures.overrideOwnerUser();
|
||||
|
@ -407,7 +412,7 @@ describe('Frontend Routing', function () {
|
|||
|
||||
after(testUtils.teardown);
|
||||
|
||||
it('should redirect without slash', function (done) {
|
||||
it('should 301 redirect with CC=1year without slash', function (done) {
|
||||
request.get('/rss')
|
||||
.expect('Location', '/rss/')
|
||||
.expect('Cache-Control', testUtils.cacheRules.year)
|
||||
|
@ -415,7 +420,7 @@ describe('Frontend Routing', function () {
|
|||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should respond with xml', function (done) {
|
||||
it('should respond with 200 & CC=public', function (done) {
|
||||
request.get('/rss/')
|
||||
.expect('Content-Type', 'text/xml; charset=utf-8')
|
||||
.expect('Cache-Control', testUtils.cacheRules['public'])
|
||||
|
@ -429,47 +434,14 @@ describe('Frontend Routing', function () {
|
|||
should.not.exist(res.headers['X-CSRF-Token']);
|
||||
should.not.exist(res.headers['set-cookie']);
|
||||
should.exist(res.headers.date);
|
||||
|
||||
var content = res.text,
|
||||
siteTitle = '<title><![CDATA[Ghost]]></title>',
|
||||
siteDescription = '<description><![CDATA[Just a blogging platform.]]></description>',
|
||||
siteUrl = '<link>http://127.0.0.1:2369/</link>',
|
||||
postTitle = '<![CDATA[Welcome to Ghost]]>',
|
||||
descStart = '<description><![CDATA[<p>You\'re live!',
|
||||
postStart = '<content:encoded><![CDATA[<p>You\'re live!',
|
||||
postEnd = 'you think :)</p>]]></content:encoded>',
|
||||
postLink = '<link>http://127.0.0.1:2369/welcome-to-ghost/</link>',
|
||||
postCreator = '<dc:creator><![CDATA[Joe Bloggs]]>',
|
||||
author = '<author>';
|
||||
|
||||
content.indexOf('<rss').should.be.above(0);
|
||||
content.indexOf(siteTitle).should.be.above(0);
|
||||
content.indexOf(siteDescription).should.be.above(0);
|
||||
content.indexOf(siteUrl).should.be.above(0);
|
||||
content.indexOf(postTitle).should.be.above(0);
|
||||
content.indexOf(descStart).should.be.above(0);
|
||||
content.indexOf(postStart).should.be.above(0);
|
||||
content.indexOf(postEnd).should.be.above(0);
|
||||
content.indexOf(postLink).should.be.above(0);
|
||||
content.indexOf(postCreator).should.be.above(0);
|
||||
content.indexOf('</rss>').should.be.above(0);
|
||||
content.indexOf(author).should.be.below(0);
|
||||
content.indexOf(postCreator).should.be.above(0);
|
||||
// The remainder of the XML is tested in the unit/xml_spec.js
|
||||
res.text.should.match(/^<\?xml version="1.0" encoding="UTF-8"\?>\n<rss/);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have as second page', function (done) {
|
||||
request.get('/rss/2/')
|
||||
// TODO this should probably redirect straight to /rss/ with 301?
|
||||
.expect('Location', '/rss/1/')
|
||||
.expect('Cache-Control', testUtils.cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should get redirected to /rss/ from /feed/', function (done) {
|
||||
it('should get 301 redirect with CC=1year to /rss/ from /feed/', function (done) {
|
||||
request.get('/feed/')
|
||||
.expect('Location', '/rss/')
|
||||
.expect('Cache-Control', testUtils.cacheRules.year)
|
||||
|
@ -477,49 +449,11 @@ describe('Frontend Routing', function () {
|
|||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
describe('More RSS', function () {
|
||||
before(function (done) {
|
||||
testUtils.fixtures.insertPosts().then(function () {
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should use meta_description and image where available', function (done) {
|
||||
var post1End = 'you think :)</p>]]></content:encoded>',
|
||||
post3Title = '<title><![CDATA[Short and Sweet]]>',
|
||||
post3DescStart = '<description><![CDATA[test stuff',
|
||||
post3ContentStart = '<content:encoded><![CDATA[<h2 id=\"testing\">testing</h2>\n\n' +
|
||||
'<img src=\"http:\/\/placekitten.com\/500\/200\"',
|
||||
post3Image = '<media:content url=\"http:\/\/placekitten.com\/500\/200\" medium=\"image\"\/>';
|
||||
|
||||
request.get('/rss/')
|
||||
.expect('Content-Type', 'text/xml; charset=utf-8')
|
||||
.expect('Cache-Control', testUtils.cacheRules['public'])
|
||||
.expect(200)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
var content = res.text,
|
||||
endIndex = content.indexOf(post1End);
|
||||
|
||||
content.indexOf('<rss').should.be.above(0);
|
||||
content.indexOf(post1End).should.be.above(0);
|
||||
content.indexOf(post3Title).should.be.above(endIndex);
|
||||
content.indexOf(post3DescStart).should.be.above(endIndex);
|
||||
content.indexOf(post3ContentStart).should.be.above(endIndex);
|
||||
content.indexOf(post3Image).should.be.above(endIndex);
|
||||
content.indexOf('</rss>').should.be.above(0);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('RSS pages', function () {
|
||||
before(function (done) {
|
||||
testUtils.fixtures.insertMorePosts(11).then(function () {
|
||||
testUtils.fixtures.insertPosts().then(function () {
|
||||
return testUtils.fixtures.insertMorePosts(11);
|
||||
}).then(function () {
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
@ -538,31 +472,6 @@ describe('Frontend Routing', function () {
|
|||
.expect(200)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should redirect page 1', function (done) {
|
||||
request.get('/rss/1/')
|
||||
.expect('Location', '/rss/')
|
||||
.expect('Cache-Control', testUtils.cacheRules['public'])
|
||||
// TODO: This should probably be a 301?
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should redirect to last page if page too high', function (done) {
|
||||
request.get('/rss/3/')
|
||||
.expect('Location', '/rss/2/')
|
||||
.expect('Cache-Control', testUtils.cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
|
||||
it('should redirect to first page if page too low', function (done) {
|
||||
request.get('/rss/0/')
|
||||
.expect('Location', '/rss/')
|
||||
.expect('Cache-Control', testUtils.cacheRules['public'])
|
||||
.expect(302)
|
||||
.end(doEnd(done));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1334,132 +1334,6 @@ describe('Frontend Controller', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('rss redirects', function () {
|
||||
var res,
|
||||
apiUsersStub;
|
||||
|
||||
beforeEach(function () {
|
||||
res = {
|
||||
locals: {version: ''},
|
||||
redirect: sandbox.spy(),
|
||||
render: sandbox.spy()
|
||||
};
|
||||
|
||||
sandbox.stub(api.posts, 'browse', function () {
|
||||
return Promise.resolve({posts: {}, meta: {pagination: {pages: 3}}});
|
||||
});
|
||||
|
||||
apiUsersStub = sandbox.stub(api.users, 'read').returns(Promise.resolve({}));
|
||||
|
||||
apiSettingsStub = sandbox.stub(api.settings, 'read');
|
||||
apiSettingsStub.withArgs('title').returns(Promise.resolve({
|
||||
settings: [{
|
||||
key: 'title',
|
||||
value: 'Test'
|
||||
}]
|
||||
}));
|
||||
apiSettingsStub.withArgs('description').returns(Promise.resolve({
|
||||
settings: [{
|
||||
key: 'description',
|
||||
value: 'Some Text'
|
||||
}]
|
||||
}));
|
||||
apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
|
||||
settings: [{
|
||||
key: 'permalinks',
|
||||
value: '/:slug/'
|
||||
}]
|
||||
}));
|
||||
});
|
||||
|
||||
it('Redirects to rss if page number is 0', function () {
|
||||
var req = {params: {page: -1}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
frontend.rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to rss if page number is 0', function () {
|
||||
var req = {params: {page: 0}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
frontend.rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to home if page number is 1', function () {
|
||||
var req = {params: {page: 1}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
frontend.rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to home if page number is 0 with subdirectory', function () {
|
||||
config.set({url: 'http://testurl.com/blog'});
|
||||
|
||||
var req = {params: {page: 0}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
frontend.rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/blog/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to home if page number is 1 with subdirectory', function () {
|
||||
config.set({url: 'http://testurl.com/blog'});
|
||||
|
||||
var req = {params: {page: 1}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
frontend.rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/blog/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to last page if page number too big', function (done) {
|
||||
config.set({url: 'http://testurl.com/'});
|
||||
|
||||
var req = {params: {page: 4}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
frontend.rss(req, res, done).then(function () {
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/rss/3/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('Redirects to last page if page number too big with subdirectory', function (done) {
|
||||
config.set({url: 'http://testurl.com/blog'});
|
||||
|
||||
var req = {params: {page: 4}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
frontend.rss(req, res, done).then(function () {
|
||||
res.redirect.calledOnce.should.be.true;
|
||||
res.redirect.calledWith('/blog/rss/3/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('private', function () {
|
||||
var req, res, config, defaultPath;
|
||||
|
||||
|
|
488
core/test/unit/rss_spec.js
Normal file
488
core/test/unit/rss_spec.js
Normal file
|
@ -0,0 +1,488 @@
|
|||
/*globals describe, before, beforeEach, afterEach, it*/
|
||||
/*jshint expr:true*/
|
||||
var should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
rewire = require('rewire'),
|
||||
_ = require('lodash'),
|
||||
Promise = require('bluebird'),
|
||||
testUtils = require('../utils'),
|
||||
// Things that get overridden
|
||||
api = require('../../server/api'),
|
||||
config = require('../../server/config'),
|
||||
origConfig = _.cloneDeep(config),
|
||||
rss = rewire('../../server/data/xml/rss');
|
||||
|
||||
// To stop jshint complaining
|
||||
should.equal(true, true);
|
||||
|
||||
// Helper function to prevent unit tests
|
||||
// from failing via timeout when they
|
||||
// should just immediately fail
|
||||
function failTest(done) {
|
||||
return function (err) {
|
||||
done(err);
|
||||
};
|
||||
}
|
||||
|
||||
describe('RSS', function () {
|
||||
var sandbox, req, res, posts;
|
||||
|
||||
before(function () {
|
||||
posts = _.filter(testUtils.DataGenerator.forKnex.posts, function filter(post) {
|
||||
return post.status === 'published' && post.page === false;
|
||||
});
|
||||
|
||||
_.each(posts, function (post) {
|
||||
post.url = '/' + post.slug + '/';
|
||||
post.author = {name: 'Joe Bloggs'};
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
sandbox = sinon.sandbox.create();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
rss = rewire('../../server/data/xml/rss');
|
||||
config.set(_.merge({}, origConfig));
|
||||
});
|
||||
|
||||
describe('Check XML', function () {
|
||||
beforeEach(function () {
|
||||
req = {
|
||||
params: {},
|
||||
originalUrl: '/rss/'
|
||||
};
|
||||
|
||||
res = {
|
||||
locals: {
|
||||
safeVersion: '0.6'
|
||||
},
|
||||
set: sinon.stub()
|
||||
};
|
||||
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
});
|
||||
|
||||
it('should get the RSS tags correct', function (done) {
|
||||
rss.__set__('getData', function () {
|
||||
return Promise.resolve({
|
||||
title: 'Test Title',
|
||||
description: 'Testing Desc',
|
||||
permalinks: '/:slug/',
|
||||
results: {posts: [], meta: {pagination: {pages: 1}}}
|
||||
});
|
||||
});
|
||||
|
||||
res.send = function send(xmlData) {
|
||||
should.exist(xmlData);
|
||||
res.set.calledWith('Content-Type', 'text/xml; charset=UTF-8').should.be.true;
|
||||
|
||||
// xml & rss tags
|
||||
xmlData.should.match(/^<\?xml version="1.0" encoding="UTF-8"\?>/);
|
||||
xmlData.should.match(/<rss/);
|
||||
xmlData.should.match(/xmlns:dc="http:\/\/purl.org\/dc\/elements\/1.1\/"/);
|
||||
xmlData.should.match(/xmlns:content="http:\/\/purl.org\/rss\/1.0\/modules\/content\/"/);
|
||||
xmlData.should.match(/xmlns:atom="http:\/\/www.w3.org\/2005\/Atom"/);
|
||||
xmlData.should.match(/version="2.0"/);
|
||||
xmlData.should.match(/xmlns:media="http:\/\/search.yahoo.com\/mrss\/"/);
|
||||
|
||||
// channel tags
|
||||
xmlData.should.match(/<channel><title><!\[CDATA\[Test Title\]\]><\/title>/);
|
||||
xmlData.should.match(/<description><!\[CDATA\[Testing Desc\]\]><\/description>/);
|
||||
xmlData.should.match(/<link>http:\/\/my-ghost-blog.com\/<\/link>/);
|
||||
xmlData.should.match(/<generator>Ghost 0.6<\/generator>/);
|
||||
xmlData.should.match(/<lastBuildDate>.*?<\/lastBuildDate>/);
|
||||
xmlData.should.match(/<atom:link href="http:\/\/my-ghost-blog.com\/rss\/" rel="self"/);
|
||||
xmlData.should.match(/type="application\/rss\+xml"\/><ttl>60<\/ttl>/);
|
||||
xmlData.should.match(/<\/channel><\/rss>$/);
|
||||
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should get the item tags correct', function (done) {
|
||||
rss.__set__('getData', function () {
|
||||
return Promise.resolve({
|
||||
title: 'Test Title',
|
||||
description: 'Testing Desc',
|
||||
permalinks: '/:slug/',
|
||||
results: {posts: posts, meta: {pagination: {pages: 1}}}
|
||||
});
|
||||
});
|
||||
|
||||
res.send = function send(xmlData) {
|
||||
should.exist(xmlData);
|
||||
|
||||
// item tags
|
||||
xmlData.should.match(/<item><title><!\[CDATA\[HTML Ipsum\]\]><\/title>/);
|
||||
xmlData.should.match(/<description><!\[CDATA\[<h1>HTML Ipsum Presents<\/h1>/);
|
||||
xmlData.should.match(/<link>http:\/\/my-ghost-blog.com\/html-ipsum\/<\/link>/);
|
||||
xmlData.should.match(/<guid isPermaLink="false">/);
|
||||
xmlData.should.match(/<\/guid><dc:creator><!\[CDATA\[Joe Bloggs\]\]><\/dc:creator>/);
|
||||
xmlData.should.match(/<pubDate>Thu, 01 Jan 2015/);
|
||||
xmlData.should.match(/<content:encoded><!\[CDATA\[<h1>HTML Ipsum Presents<\/h1><p><strong>Pellentes/);
|
||||
xmlData.should.match(/<\/code><\/pre>\]\]><\/content:encoded><\/item>/);
|
||||
xmlData.should.not.match(/<author>/);
|
||||
|
||||
// basic structure check
|
||||
var postEnd = '<\/code><\/pre>\]\]><\/content:encoded>',
|
||||
firstIndex = xmlData.indexOf(postEnd);
|
||||
|
||||
// The first title should be before the first content
|
||||
xmlData.indexOf('HTML Ipsum').should.be.below(firstIndex);
|
||||
// The second title should be after the first content
|
||||
xmlData.indexOf('Ghostly Kitchen Sink').should.be.above(firstIndex);
|
||||
|
||||
// done
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should use meta_description and image where available', function (done) {
|
||||
rss.__set__('getData', function () {
|
||||
return Promise.resolve({
|
||||
title: 'Test Title',
|
||||
description: 'Testing Desc',
|
||||
permalinks: '/:slug/',
|
||||
results: {posts: [posts[2]], meta: {pagination: {pages: 1}}}
|
||||
});
|
||||
});
|
||||
|
||||
res.send = function send(xmlData) {
|
||||
should.exist(xmlData);
|
||||
|
||||
// special/optional tags
|
||||
xmlData.should.match(/<title><!\[CDATA\[Short and Sweet\]\]>/);
|
||||
xmlData.should.match(/<description><!\[CDATA\[test stuff/);
|
||||
xmlData.should.match(/<content:encoded><!\[CDATA\[<h2 id="testing">testing<\/h2>\n\n/);
|
||||
xmlData.should.match(/<img src="http:\/\/placekitten.com\/500\/200"/);
|
||||
xmlData.should.match(/<media:content url="http:\/\/placekitten.com\/500\/200" medium="image"\/>/);
|
||||
|
||||
// done
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should process urls correctly', function (done) {
|
||||
rss.__set__('getData', function () {
|
||||
return Promise.resolve({
|
||||
title: 'Test Title',
|
||||
description: 'Testing Desc',
|
||||
permalinks: '/:slug/',
|
||||
results: {posts: [posts[3]], meta: {pagination: {pages: 1}}}
|
||||
});
|
||||
});
|
||||
|
||||
res.send = function send(xmlData) {
|
||||
should.exist(xmlData);
|
||||
|
||||
// anchor URL - <a href="#nowhere" title="Anchor URL">
|
||||
xmlData.should.match(/<a href="http:\/\/my-ghost-blog.com\/not-so-short-bit-complex\/#nowhere" title="Anchor URL">/);
|
||||
|
||||
// relative URL - <a href="/about#nowhere" title="Relative URL">
|
||||
xmlData.should.match(/<a href="http:\/\/my-ghost-blog.com\/about#nowhere" title="Relative URL">/);
|
||||
|
||||
// absolute URL - <a href="http://somewhere.com/link#nowhere" title="Absolute URL">
|
||||
xmlData.should.match(/<a href="http:\/\/somewhere.com\/link#nowhere" title="Absolute URL">/);
|
||||
|
||||
// done
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should process urls correctly with subdirectory', function (done) {
|
||||
config.set({url: 'http://my-ghost-blog.com/blog/'});
|
||||
rss.__set__('getData', function () {
|
||||
return Promise.resolve({
|
||||
title: 'Test Title',
|
||||
description: 'Testing Desc',
|
||||
permalinks: '/:slug/',
|
||||
results: {posts: [posts[3]], meta: {pagination: {pages: 1}}}
|
||||
});
|
||||
});
|
||||
|
||||
res.send = function send(xmlData) {
|
||||
should.exist(xmlData);
|
||||
|
||||
// anchor URL - <a href="#nowhere" title="Anchor URL">
|
||||
xmlData.should.match(/<a href="http:\/\/my-ghost-blog.com\/blog\/not-so-short-bit-complex\/#nowhere" title="Anchor URL">/);
|
||||
|
||||
// relative URL - <a href="/about#nowhere" title="Relative URL">
|
||||
xmlData.should.match(/<a href="http:\/\/my-ghost-blog.com\/blog\/about#nowhere" title="Relative URL">/);
|
||||
|
||||
// absolute URL - <a href="http://somewhere.com/link#nowhere" title="Absolute URL">
|
||||
xmlData.should.match(/<a href="http:\/\/somewhere.com\/link#nowhere" title="Absolute URL">/);
|
||||
|
||||
// done
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
});
|
||||
});
|
||||
|
||||
describe('dataBuilder', function () {
|
||||
var apiSettingsStub, apiBrowseStub;
|
||||
beforeEach(function () {
|
||||
apiSettingsStub = sandbox.stub(api.settings, 'read');
|
||||
apiSettingsStub.withArgs('title').returns(Promise.resolve({
|
||||
settings: [{
|
||||
key: 'title',
|
||||
value: 'Test'
|
||||
}]
|
||||
}));
|
||||
apiSettingsStub.withArgs('description').returns(Promise.resolve({
|
||||
settings: [{
|
||||
key: 'description',
|
||||
value: 'Some Text'
|
||||
}]
|
||||
}));
|
||||
apiSettingsStub.withArgs('permalinks').returns(Promise.resolve({
|
||||
settings: [{
|
||||
key: 'permalinks',
|
||||
value: '/:slug/'
|
||||
}]
|
||||
}));
|
||||
|
||||
req = {
|
||||
params: {},
|
||||
originalUrl: '/rss/'
|
||||
};
|
||||
|
||||
res = {
|
||||
locals: {
|
||||
safeVersion: '0.6'
|
||||
},
|
||||
set: sinon.stub()
|
||||
};
|
||||
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
});
|
||||
|
||||
it('should process the data correctly for the index feed', function (done) {
|
||||
apiBrowseStub = sandbox.stub(api.posts, 'browse', function () {
|
||||
return Promise.resolve({posts: [], meta: {pagination: {pages: 3}}});
|
||||
});
|
||||
res.send = function send(xmlData) {
|
||||
apiSettingsStub.calledThrice.should.be.true;
|
||||
apiBrowseStub.calledOnce.should.be.true;
|
||||
apiBrowseStub.calledWith({page: 1, include: 'author,tags,fields'}).should.be.true;
|
||||
xmlData.should.match(/<channel><title><!\[CDATA\[Test\]\]><\/title>/);
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should process the data correctly for a tag feed', function (done) {
|
||||
// setup
|
||||
apiBrowseStub = sandbox.stub(api.posts, 'browse', function () {
|
||||
return Promise.resolve({posts: [], meta: {pagination: {pages: 3}, filters: {tags: [{name: 'Magic'}]}}});
|
||||
});
|
||||
req.originalUrl = '/tag/magic/rss/';
|
||||
req.params.slug = 'magic';
|
||||
|
||||
// test
|
||||
res.send = function send(xmlData) {
|
||||
apiSettingsStub.calledThrice.should.be.true;
|
||||
apiBrowseStub.calledOnce.should.be.true;
|
||||
apiBrowseStub.calledWith({page: 1, tag: 'magic', include: 'author,tags,fields'}).should.be.true;
|
||||
xmlData.should.match(/<channel><title><!\[CDATA\[Magic - Test\]\]><\/title>/);
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
});
|
||||
|
||||
it('should process the data correctly for an author feed', function (done) {
|
||||
// setup
|
||||
apiBrowseStub = sandbox.stub(api.posts, 'browse', function () {
|
||||
return Promise.resolve({posts: [], meta: {pagination: {pages: 3}, filters: {author: {name: 'Joe Blogs'}}}});
|
||||
});
|
||||
req.originalUrl = '/author/joe/rss/';
|
||||
req.params.slug = 'joe';
|
||||
|
||||
// test
|
||||
res.send = function send(xmlData) {
|
||||
apiSettingsStub.calledThrice.should.be.true;
|
||||
apiBrowseStub.calledOnce.should.be.true;
|
||||
apiBrowseStub.calledWith({page: 1, author: 'joe', include: 'author,tags,fields'}).should.be.true;
|
||||
xmlData.should.match(/<channel><title><!\[CDATA\[Joe Blogs - Test\]\]><\/title>/);
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
});
|
||||
});
|
||||
|
||||
describe('caching', function () {
|
||||
beforeEach(function () {
|
||||
req = {
|
||||
params: {},
|
||||
originalUrl: '/rss/'
|
||||
};
|
||||
|
||||
res = {
|
||||
locals: {
|
||||
safeVersion: '0.6'
|
||||
},
|
||||
set: sinon.stub()
|
||||
};
|
||||
|
||||
config.set({url: 'http://my-ghost-blog.com'});
|
||||
});
|
||||
|
||||
it('should not rebuild xml for same data and url', function (done) {
|
||||
var xmlData;
|
||||
rss.__set__('getData', function () {
|
||||
return Promise.resolve({
|
||||
title: 'Test Title',
|
||||
description: 'Testing Desc',
|
||||
permalinks: '/:slug/',
|
||||
results: {posts: [], meta: {pagination: {pages: 1}}}
|
||||
});
|
||||
});
|
||||
|
||||
function secondCall() {
|
||||
res.send = function sendFirst(data) {
|
||||
// The data should be identical, no changing lastBuildDate
|
||||
data.should.equal(xmlData);
|
||||
|
||||
// Now call done!
|
||||
done();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
}
|
||||
|
||||
function firstCall() {
|
||||
res.send = function sendFirst(data) {
|
||||
xmlData = data;
|
||||
|
||||
// Call RSS again to check that we didn't rebuild
|
||||
secondCall();
|
||||
};
|
||||
|
||||
rss(req, res, failTest(done));
|
||||
}
|
||||
|
||||
firstCall();
|
||||
});
|
||||
});
|
||||
|
||||
describe('redirects', function () {
|
||||
beforeEach(function () {
|
||||
res = {
|
||||
locals: {version: ''},
|
||||
redirect: sandbox.spy(),
|
||||
render: sandbox.spy()
|
||||
};
|
||||
|
||||
rss.__set__('getData', function () {
|
||||
return Promise.resolve({
|
||||
title: 'Test',
|
||||
description: 'Testing',
|
||||
permalinks: '/:slug/',
|
||||
results: {posts: [], meta: {pagination: {pages: 3}}}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Redirects to /rss/ if page number is -1', function () {
|
||||
req = {params: {page: -1}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to /rss/ if page number is 0', function () {
|
||||
req = {params: {page: 0}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to /rss/ if page number is 1', function () {
|
||||
req = {params: {page: 1}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to /blog/rss/ if page number is 0 with subdirectory', function () {
|
||||
config.set({url: 'http://testurl.com/blog'});
|
||||
|
||||
req = {params: {page: 0}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/blog/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to /blog/rss/ if page number is 1 with subdirectory', function () {
|
||||
config.set({url: 'http://testurl.com/blog'});
|
||||
|
||||
req = {params: {page: 1}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
rss(req, res, null);
|
||||
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/blog/rss/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
});
|
||||
|
||||
it('Redirects to last page if page number too big', function (done) {
|
||||
config.set({url: 'http://testurl.com/'});
|
||||
|
||||
req = {params: {page: 4}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
rss(req, res, failTest(done)).then(function () {
|
||||
res.redirect.called.should.be.true;
|
||||
res.redirect.calledWith('/rss/3/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('Redirects to last page if page number too big with subdirectory', function (done) {
|
||||
config.set({url: 'http://testurl.com/blog'});
|
||||
|
||||
req = {params: {page: 4}, route: {path: '/rss/:page/'}};
|
||||
req.originalUrl = req.route.path.replace(':page', req.params.page);
|
||||
|
||||
rss(req, res, failTest(done)).then(function () {
|
||||
res.redirect.calledOnce.should.be.true;
|
||||
res.redirect.calledWith('/blog/rss/3/').should.be.true;
|
||||
res.render.called.should.be.false;
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -38,7 +38,7 @@ DataGenerator.Content = {
|
|||
{
|
||||
title: "Not so short, bit complex",
|
||||
slug: "not-so-short-bit-complex",
|
||||
markdown: "<p><nav><ul><li><a href=\"#nowhere\" title=\"Lorum ipsum dolor sit amet\">Lorem</a></li><li><a href=\"#nowhere\" title=\"Aliquam tincidunt mauris eu risus\">Aliquam</a></li><li><a href=\"#nowhere\" title=\"Morbi in sem quis dui placerat ornare\">Morbi</a></li><li><a href=\"#nowhere\" title=\"Praesent dapibus, neque id cursus faucibus\">Praesent</a></li><li><a href=\"#nowhere\" title=\"Pellentesque fermentum dolor\">Pellentesque</a></li></ul></nav><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p><table><thead><tr><th>1</th><th>2</th><th>3</th><th>4</th></tr></thead><tbody><tr><td>a</td><td>b</td><td>c</td><td>d</td></tr><tr><td>e</td><td>f</td><td>g</td><td>h</td></tr><tr><td>i</td><td>j</td><td>k</td><td>l</td></tr></tbody></table><dl><dt>Definition list</dt><dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd><dt>Lorem ipsum dolor sit amet</dt><dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd></dl><ul><li>Morbi in sem quis dui placerat ornare. Pellentesque odio nisi, euismod in, pharetra a, ultricies in, diam. Sed arcu. Cras consequat.</li><li>Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus.</li><li>Phasellus ultrices nulla quis nibh. Quisque a lectus. Donec consectetuer ligula vulputate sem tristique cursus. Nam nulla quam, gravida non, commodo a, sodales sit amet, nisi.</li><li>Pellentesque fermentum dolor. Aliquam quam lectus, facilisis auctor, ultrices ut, elementum vulputate, nunc.</li></ul></p>"
|
||||
markdown: "<p><nav><ul><li><a href=\"#nowhere\" title=\"Anchor URL\">Lorem</a></li><li><a href=\"/about#nowhere\" title=\"Relative URL\">Aliquam</a></li><li><a href=\"http://somewhere.com/link#nowhere\" title=\"Absolute URL\">Morbi</a></li><li><a href=\"#nowhere\" title=\"Praesent dapibus, neque id cursus faucibus\">Praesent</a></li><li><a href=\"#nowhere\" title=\"Pellentesque fermentum dolor\">Pellentesque</a></li></ul></nav><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p><table><thead><tr><th>1</th><th>2</th><th>3</th><th>4</th></tr></thead><tbody><tr><td>a</td><td>b</td><td>c</td><td>d</td></tr><tr><td>e</td><td>f</td><td>g</td><td>h</td></tr><tr><td>i</td><td>j</td><td>k</td><td>l</td></tr></tbody></table><dl><dt>Definition list</dt><dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd><dt>Lorem ipsum dolor sit amet</dt><dd>Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</dd></dl><ul><li>Morbi in sem quis dui placerat ornare. Pellentesque odio nisi, euismod in, pharetra a, ultricies in, diam. Sed arcu. Cras consequat.</li><li>Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus.</li><li>Phasellus ultrices nulla quis nibh. Quisque a lectus. Donec consectetuer ligula vulputate sem tristique cursus. Nam nulla quam, gravida non, commodo a, sodales sit amet, nisi.</li><li>Pellentesque fermentum dolor. Aliquam quam lectus, facilisis auctor, ultrices ut, elementum vulputate, nunc.</li></ul></p>"
|
||||
},
|
||||
{
|
||||
title: "This is a static page",
|
||||
|
|
Loading…
Add table
Reference in a new issue