Ghost/test/unit/services/sitemap/generator.test.js
Hannah Wolfe f08a55c21f
Renamed tests to .test.js & updated commands
refs: https://github.com/TryGhost/Team/issues/856
refs: https://github.com/TryGhost/Team/issues/756

- The .test.js extension is better than _spec.js as it's more obvious that it's an extension
- It also meaans we can use the --extension parameter in mocha, which should result in a better default behaviour for `yarn test`
- It also highlights that some of our tests were named incorrectly and were not (and still will not be) run (see https://github.com/TryGhost/Team/issues/856)
- Note: even with this change, `yarn test` is throwing errors, I believe because of this issue https://github.com/TryGhost/Team/issues/756
2021-07-06 20:45:01 +01:00

241 lines
9.4 KiB
JavaScript

const should = require('should');
const sinon = require('sinon');
const ObjectId = require('bson-objectid');
const _ = require('lodash');
const testUtils = require('../../../utils');
const urlUtils = require('../../../../core/shared/url-utils');
const IndexGenerator = require('../../../../core/frontend/services/sitemap/index-generator');
const PostGenerator = require('../../../../core/frontend/services/sitemap/post-generator');
const PageGenerator = require('../../../../core/frontend/services/sitemap/page-generator');
const TagGenerator = require('../../../../core/frontend/services/sitemap/tag-generator');
const UserGenerator = require('../../../../core/frontend/services/sitemap/user-generator');
should.Assertion.add('ValidUrlNode', function (options) {
// Check urlNode looks correct
/*eslint no-invalid-this: "off"*/
let urlNode = this.obj;
let flatNode;
urlNode.should.be.an.Object().with.key('url');
urlNode.url.should.be.an.Array();
if (options.withImage) {
urlNode.url.should.have.lengthOf(3);
} else {
urlNode.url.should.have.lengthOf(2);
}
/**
* A urlNode looks something like:
* { url:
* [ { loc: 'http://127.0.0.1:2369/author/' },
* { lastmod: '2014-12-22T11:54:00.100Z' },
* { 'image:image': [
* { 'image:loc': 'post-100.jpg' },
* { 'image:caption': 'post-100.jpg' }
* ] }
* ] }
*/
flatNode = _.extend.apply(_, urlNode.url);
if (options.withImage) {
flatNode.should.be.an.Object().with.keys('loc', 'lastmod', 'image:image');
} else {
flatNode.should.be.an.Object().with.keys('loc', 'lastmod');
}
});
describe('Generators', function () {
let generator;
afterEach(function () {
sinon.restore();
});
describe('IndexGenerator', function () {
beforeEach(function () {
generator = new IndexGenerator({
types: {
posts: new PostGenerator(),
pages: new PageGenerator(),
tags: new TagGenerator(),
authors: new UserGenerator()
}
});
});
describe('fn: getXml', function () {
it('default', function () {
const xml = generator.getXml();
xml.should.match(/sitemap-tags.xml/);
xml.should.match(/sitemap-posts.xml/);
xml.should.match(/sitemap-pages.xml/);
xml.should.match(/sitemap-authors.xml/);
});
});
});
describe('PostGenerator', function () {
beforeEach(function () {
generator = new PostGenerator();
});
describe('fn: createNodeFromDatum', function () {
it('adds an image:image element if post has a cover image', function () {
const urlNode = generator.createUrlNodeFromDatum('https://myblog.com/test/', testUtils.DataGenerator.forKnex.createPost({
feature_image: 'post-100.jpg',
page: false,
slug: 'test'
}));
urlNode.should.be.a.ValidUrlNode({withImage: true});
});
});
describe('fn: getXml', function () {
beforeEach(function () {
sinon.stub(urlUtils, 'urlFor');
});
it('get cached xml', function () {
sinon.spy(generator, 'generateXmlFromNodes');
generator.siteMapContent = 'something';
generator.getXml().should.eql('something');
generator.siteMapContent = null;
generator.generateXmlFromNodes.called.should.eql(false);
});
it('compare content output', function () {
let idxFirst;
let idxSecond;
let idxThird;
urlUtils.urlFor.withArgs('image', {image: 'post-100.jpg'}, true).returns('http://my-ghost-blog.com/images/post-100.jpg');
urlUtils.urlFor.withArgs('image', {image: 'post-200.jpg'}, true).returns('http://my-ghost-blog.com/images/post-200.jpg');
urlUtils.urlFor.withArgs('image', {image: 'post-300.jpg'}, true).returns('http://my-ghost-blog.com/images/post-300.jpg');
urlUtils.urlFor.withArgs('sitemap_xsl', true).returns('http://my-ghost-blog.com/sitemap.xsl');
generator.addUrl('http://my-ghost-blog.com/url/100/', testUtils.DataGenerator.forKnex.createPost({
feature_image: 'post-100.jpg',
created_at: (Date.UTC(2014, 11, 22, 12) - 360000) + 100,
updated_at: null,
published_at: null,
slug: '100'
}));
generator.addUrl('http://my-ghost-blog.com/url/200/', testUtils.DataGenerator.forKnex.createPost({
created_at: (Date.UTC(2014, 11, 22, 12) - 360000) + 200,
updated_at: null,
published_at: null,
slug: '200'
}));
generator.addUrl('http://my-ghost-blog.com/url/300/', testUtils.DataGenerator.forKnex.createPost({
created_at: (Date.UTC(2014, 11, 22, 12) - 360000) + 300,
feature_image: 'post-300.jpg',
updated_at: null,
published_at: null,
slug: '300'
}));
const xml = generator.getXml();
xml.should.containEql('<loc>http://my-ghost-blog.com/url/100/</loc>');
xml.should.containEql('<loc>http://my-ghost-blog.com/url/200/</loc>');
xml.should.containEql('<loc>http://my-ghost-blog.com/url/300/</loc>');
xml.should.containEql('<image:loc>http://my-ghost-blog.com/images/post-100.jpg</image:loc>');
// This should NOT be present
xml.should.not.containEql('<image:loc>http://my-ghost-blog.com/images/post-200.jpg</image:loc>');
xml.should.containEql('<image:loc>http://my-ghost-blog.com/images/post-300.jpg</image:loc>');
// Validate order newest to oldest
idxFirst = xml.indexOf('<loc>http://my-ghost-blog.com/url/300/</loc>');
idxSecond = xml.indexOf('<loc>http://my-ghost-blog.com/url/200/</loc>');
idxThird = xml.indexOf('<loc>http://my-ghost-blog.com/url/100/</loc>');
idxFirst.should.be.below(idxSecond);
idxSecond.should.be.below(idxThird);
});
});
describe('fn: removeUrl', function () {
let post;
beforeEach(function () {
post = testUtils.DataGenerator.forKnex.createPost();
generator.nodeLookup[post.id] = 'node';
});
afterEach(function () {
generator.nodeLookup = {};
generator.nodeTimeLookup = {};
});
it('remove none existend url', function () {
generator.removeUrl('https://myblog.com/blog/podcast/featured/', testUtils.DataGenerator.forKnex.createPost());
Object.keys(generator.nodeLookup).length.should.eql(1);
});
it('remove existing url', function () {
generator.removeUrl('https://myblog.com/blog/test/', post);
Object.keys(generator.nodeLookup).length.should.eql(0);
});
});
});
describe('PageGenerator', function () {
beforeEach(function () {
generator = new PageGenerator();
});
describe('fn: getXml', function () {
it('add', function () {
generator.addUrl('http://my-ghost-blog.com/home/', {id: 'identifier1', staticRoute: true});
generator.addUrl('http://my-ghost-blog.com/magic/', {id: 'identifier2', staticRoute: false});
generator.addUrl('http://my-ghost-blog.com/subscribe/', {id: ObjectId().toHexString(), page: 1});
generator.getXml();
generator.siteMapContent.should.containEql('<loc>http://my-ghost-blog.com/home/</loc>');
generator.siteMapContent.should.containEql('<loc>http://my-ghost-blog.com/magic/</loc>');
generator.siteMapContent.should.containEql('<loc>http://my-ghost-blog.com/subscribe/</loc>');
// <loc> should exist exactly one time
generator.siteMapContent.match(/<loc>/g).length.should.eql(3);
});
});
});
describe('TagGenerator', function () {
beforeEach(function () {
generator = new TagGenerator();
});
});
describe('UserGenerator', function () {
beforeEach(function () {
generator = new UserGenerator();
});
describe('fn: validateImageUrl', function () {
it('image url is localhost', function () {
generator.validateImageUrl('http://localhost:2368/content/images/1.jpg').should.be.true();
});
it('image url is https', function () {
generator.validateImageUrl('https://myblog.com/content/images/1.png').should.be.true();
});
it('image url is external', function () {
generator.validateImageUrl('https://myblog.com/1.jpg').should.be.true();
});
it('no host', function () {
generator.validateImageUrl('/content/images/1.jpg').should.be.false();
});
});
});
});