mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Content API v2 date formatting (#10095)
closes #10065 - Added UTC offset to dates returned by Content API - Added test checking new format is compatible with Admin API - Refactored output serializer mapping logic
This commit is contained in:
parent
7b38986316
commit
ec03b3cfc5
14 changed files with 488 additions and 132 deletions
|
@ -1,5 +1,5 @@
|
|||
const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:pages');
|
||||
const url = require('./utils/url');
|
||||
const mapper = require('./utils/mapper');
|
||||
|
||||
module.exports = {
|
||||
all(models, apiConfig, frame) {
|
||||
|
@ -7,7 +7,7 @@ module.exports = {
|
|||
|
||||
if (models.meta) {
|
||||
frame.response = {
|
||||
pages: models.data.map(model => url.forPost(model.id, model.toJSON(frame.options), frame.options)),
|
||||
pages: models.data.map(model => mapper.mapPost(model, frame)),
|
||||
meta: models.meta
|
||||
};
|
||||
|
||||
|
@ -15,7 +15,7 @@ module.exports = {
|
|||
}
|
||||
|
||||
frame.response = {
|
||||
pages: [url.forPost(models.id, models.toJSON(frame.options), frame.options)]
|
||||
pages: [mapper.mapPost(models, frame)]
|
||||
};
|
||||
|
||||
debug(frame.response);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:posts');
|
||||
const url = require('./utils/url');
|
||||
const mapper = require('./utils/mapper');
|
||||
|
||||
module.exports = {
|
||||
all(models, apiConfig, frame) {
|
||||
|
@ -12,7 +12,7 @@ module.exports = {
|
|||
|
||||
if (models.meta) {
|
||||
frame.response = {
|
||||
posts: models.data.map(model => url.forPost(model.id, model.toJSON(frame.options), frame.options)),
|
||||
posts: models.data.map(model => mapper.mapPost(model, frame)),
|
||||
meta: models.meta
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,7 @@ module.exports = {
|
|||
}
|
||||
|
||||
frame.response = {
|
||||
posts: [url.forPost(models.id, models.toJSON(frame.options), frame.options)]
|
||||
posts: [mapper.mapPost(models, frame)]
|
||||
};
|
||||
|
||||
debug(frame.response);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:tags');
|
||||
const url = require('./utils/url');
|
||||
const mapper = require('./utils/mapper');
|
||||
|
||||
module.exports = {
|
||||
all(models, apiConfig, frame) {
|
||||
|
@ -11,7 +11,7 @@ module.exports = {
|
|||
|
||||
if (models.meta) {
|
||||
frame.response = {
|
||||
tags: models.data.map(model => url.forTag(model.id, model.toJSON(frame.options), frame.options)),
|
||||
tags: models.data.map(model => mapper.mapTag(model, frame)),
|
||||
meta: models.meta
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@ module.exports = {
|
|||
}
|
||||
|
||||
frame.response = {
|
||||
tags: [url.forTag(models.id, models.toJSON(frame.options), frame.options)]
|
||||
tags: [mapper.mapTag(models, frame)]
|
||||
};
|
||||
|
||||
debug(frame.response);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:users');
|
||||
const common = require('../../../../../lib/common');
|
||||
const url = require('./utils/url');
|
||||
const mapper = require('./utils/mapper');
|
||||
|
||||
module.exports = {
|
||||
browse(models, apiConfig, frame) {
|
||||
debug('browse');
|
||||
|
||||
frame.response = {
|
||||
users: models.data.map(model => url.forUser(model.id, model.toJSON(frame.options), frame.options)),
|
||||
users: models.data.map(model => mapper.mapUser(model, frame)),
|
||||
meta: models.meta
|
||||
};
|
||||
|
||||
|
@ -18,7 +18,7 @@ module.exports = {
|
|||
debug('read');
|
||||
|
||||
frame.response = {
|
||||
users: [url.forUser(model.id, model.toJSON(frame.options), frame.options)]
|
||||
users: [mapper.mapUser(model, frame)]
|
||||
};
|
||||
|
||||
debug(frame.response);
|
||||
|
|
32
core/server/api/v2/utils/serializers/output/utils/date.js
Normal file
32
core/server/api/v2/utils/serializers/output/utils/date.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const moment = require('moment-timezone');
|
||||
const settingsCache = require('../../../../../../services/settings/cache');
|
||||
|
||||
const format = (date) => {
|
||||
return moment(date)
|
||||
.tz(settingsCache.get('active_timezone'))
|
||||
.toISOString(true);
|
||||
};
|
||||
|
||||
const forPost = (attrs) => {
|
||||
['created_at', 'updated_at', 'published_at'].forEach((field) => {
|
||||
if (attrs[field]) {
|
||||
attrs[field] = format(attrs[field]);
|
||||
}
|
||||
});
|
||||
|
||||
return attrs;
|
||||
};
|
||||
|
||||
const forTag = (attrs) => {
|
||||
['created_at', 'updated_at'].forEach((field) => {
|
||||
if (attrs[field]) {
|
||||
attrs[field] = format(attrs[field]);
|
||||
}
|
||||
});
|
||||
|
||||
return attrs;
|
||||
};
|
||||
|
||||
module.exports.format = format;
|
||||
module.exports.forPost = forPost;
|
||||
module.exports.forTag = forTag;
|
61
core/server/api/v2/utils/serializers/output/utils/mapper.js
Normal file
61
core/server/api/v2/utils/serializers/output/utils/mapper.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
const utils = require('../../../index');
|
||||
const url = require('./url');
|
||||
const date = require('./date');
|
||||
|
||||
const mapPost = (model, frame) => {
|
||||
const jsonModel = model.toJSON(frame.options);
|
||||
|
||||
url.forPost(model.id, jsonModel, frame.options);
|
||||
|
||||
if (utils.isContentAPI(frame)) {
|
||||
date.forPost(jsonModel);
|
||||
}
|
||||
|
||||
if (frame.options && frame.options.withRelated) {
|
||||
frame.options.withRelated.forEach((relation) => {
|
||||
// @NOTE: this block also decorates primary_tag/primary_author objects as they
|
||||
// are being passed by reference in tags/authors. Might be refactored into more explicit call
|
||||
// in the future, but is good enough for current use-case
|
||||
if (relation === 'tags' && jsonModel.tags) {
|
||||
jsonModel.tags = jsonModel.tags.map(tag => url.forTag(tag.id, tag));
|
||||
|
||||
if (utils.isContentAPI(frame)) {
|
||||
jsonModel.tags = jsonModel.tags.map(tag => date.forTag(tag));
|
||||
}
|
||||
}
|
||||
|
||||
if (relation === 'author' && jsonModel.author) {
|
||||
jsonModel.author = url.forUser(jsonModel.author.id, jsonModel.author);
|
||||
}
|
||||
|
||||
if (relation === 'authors' && jsonModel.authors) {
|
||||
jsonModel.authors = jsonModel.authors.map(author => url.forUser(author.id, author));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return jsonModel;
|
||||
};
|
||||
|
||||
const mapUser = (model, frame) => {
|
||||
const jsonModel = model.toJSON(frame.options);
|
||||
|
||||
url.forUser(model.id, jsonModel);
|
||||
|
||||
return jsonModel;
|
||||
};
|
||||
|
||||
const mapTag = (model, frame) => {
|
||||
const jsonModel = model.toJSON(frame.options);
|
||||
url.forTag(model.id, jsonModel);
|
||||
|
||||
if (utils.isContentAPI(frame)) {
|
||||
date.forTag(jsonModel);
|
||||
}
|
||||
|
||||
return jsonModel;
|
||||
};
|
||||
|
||||
module.exports.mapPost = mapPost;
|
||||
module.exports.mapUser = mapUser;
|
||||
module.exports.mapTag = mapTag;
|
|
@ -36,25 +36,6 @@ const forPost = (id, attrs, options) => {
|
|||
delete attrs.url;
|
||||
}
|
||||
|
||||
if (options && options.withRelated) {
|
||||
options.withRelated.forEach((relation) => {
|
||||
// @NOTE: this block also decorates primary_tag/primary_author objects as they
|
||||
// are being passed by reference in tags/authors. Might be refactored into more explicit call
|
||||
// in the future, but is good enough for current use-case
|
||||
if (relation === 'tags' && attrs.tags) {
|
||||
attrs.tags = attrs.tags.map(tag => forTag(tag.id, tag));
|
||||
}
|
||||
|
||||
if (relation === 'author' && attrs.author) {
|
||||
attrs.author = forUser(attrs.author.id, attrs.author, options);
|
||||
}
|
||||
|
||||
if (relation === 'authors' && attrs.authors) {
|
||||
attrs.authors = attrs.authors.map(author => forUser(author.id, author, options));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return attrs;
|
||||
};
|
||||
|
||||
|
|
|
@ -387,7 +387,6 @@ describe('Posts API V2', function () {
|
|||
res.body.posts[0].title.should.eql(post.title);
|
||||
res.body.posts[0].status.should.eql(post.status);
|
||||
res.body.posts[0].published_at.should.eql('2016-05-30T07:00:00.000Z');
|
||||
res.body.posts[0].published_at = '2016-05-30T09:00:00.000Z';
|
||||
res.body.posts[0].created_at.should.not.eql(post.created_at.toISOString());
|
||||
res.body.posts[0].updated_at.should.not.eql(post.updated_at.toISOString());
|
||||
res.body.posts[0].updated_by.should.not.eql(post.updated_by);
|
||||
|
@ -395,10 +394,13 @@ describe('Posts API V2', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('published post', function () {
|
||||
it('published post with response timestamps in UTC format respecting original UTC offset', function () {
|
||||
const post = {
|
||||
posts: [{
|
||||
status: 'published'
|
||||
status: 'published',
|
||||
published_at: '2016-05-31T07:00:00.000+06:00',
|
||||
created_at: '2016-05-30T03:00:00.000Z',
|
||||
updated_at: '2016-05-30T07:00:00.000'
|
||||
}]
|
||||
};
|
||||
|
||||
|
@ -413,6 +415,10 @@ describe('Posts API V2', function () {
|
|||
testUtils.API.checkResponse(res.body.posts[0], 'post');
|
||||
res.body.posts[0].status.should.eql('published');
|
||||
res.headers['x-cache-invalidate'].should.eql('/*');
|
||||
|
||||
res.body.posts[0].published_at.should.eql('2016-05-31T01:00:00.000Z');
|
||||
res.body.posts[0].created_at.should.eql('2016-05-30T03:00:00.000Z');
|
||||
res.body.posts[0].updated_at.should.eql('2016-05-30T07:00:00.000Z');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
54
core/test/unit/api/v2/utils/serializers/output/pages_spec.js
Normal file
54
core/test/unit/api/v2/utils/serializers/output/pages_spec.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const testUtils = require('../../../../../../utils');
|
||||
const mapper = require('../../../../../../../server/api/v2/utils/serializers/output/utils/mapper');
|
||||
const serializers = require('../../../../../../../server/api/v2/utils/serializers');
|
||||
|
||||
const sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Unit: v2/utils/serializers/output/pages', () => {
|
||||
let pageModel;
|
||||
|
||||
beforeEach(() => {
|
||||
pageModel = (data) => {
|
||||
return Object.assign(data, {toJSON: sandbox.stub().returns(data)});
|
||||
};
|
||||
|
||||
sandbox.stub(mapper, 'mapPost').returns({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('calls the mapper', () => {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
options: {
|
||||
withRelated: ['tags', 'authors'],
|
||||
context: {
|
||||
private: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const ctrlResponse = {
|
||||
data: [
|
||||
pageModel(testUtils.DataGenerator.forKnex.createPost({
|
||||
id: 'id1',
|
||||
page: true
|
||||
})),
|
||||
pageModel(testUtils.DataGenerator.forKnex.createPost({
|
||||
id: 'id2',
|
||||
page: true
|
||||
}))
|
||||
],
|
||||
meta: {}
|
||||
};
|
||||
|
||||
serializers.output.pages.all(ctrlResponse, apiConfig, frame);
|
||||
|
||||
mapper.mapPost.callCount.should.equal(2);
|
||||
mapper.mapPost.getCall(0).args.should.eql([ctrlResponse.data[0], frame]);
|
||||
});
|
||||
});
|
|
@ -1,121 +1,48 @@
|
|||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const testUtils = require('../../../../../../utils');
|
||||
const urlService = require('../../../../../../../server/services/url');
|
||||
const mapper = require('../../../../../../../server/api/v2/utils/serializers/output/utils/mapper');
|
||||
const serializers = require('../../../../../../../server/api/v2/utils/serializers');
|
||||
|
||||
const sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Unit: v2/utils/serializers/output/posts', function () {
|
||||
describe('Unit: v2/utils/serializers/output/posts', () => {
|
||||
let postModel;
|
||||
|
||||
beforeEach(function () {
|
||||
beforeEach(() => {
|
||||
postModel = (data) => {
|
||||
return Object.assign(data, {toJSON: sandbox.stub().returns(data)});
|
||||
};
|
||||
|
||||
sandbox.stub(urlService, 'getUrlByResourceId').returns('getUrlByResourceId');
|
||||
sandbox.stub(urlService.utils, 'urlFor').returns('urlFor');
|
||||
sandbox.stub(urlService.utils, 'makeAbsoluteUrls').returns({html: sandbox.stub()});
|
||||
sandbox.stub(mapper, 'mapPost').returns({});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('Ensure absolute urls are returned by default', function () {
|
||||
it('meta & models & relations', function () {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
options: {
|
||||
withRelated: ['tags', 'authors']
|
||||
it('calls the mapper', () => {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
options: {
|
||||
withRelated: ['tags', 'authors'],
|
||||
context: {
|
||||
private: false
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const ctrlResponse = {
|
||||
data: [
|
||||
postModel(testUtils.DataGenerator.forKnex.createPost({
|
||||
id: 'id1',
|
||||
feature_image: 'value',
|
||||
tags: [{
|
||||
id: 'id3',
|
||||
feature_image: 'value'
|
||||
}],
|
||||
authors: [{
|
||||
id: 'id4',
|
||||
name: 'Ghosty'
|
||||
}]
|
||||
})),
|
||||
postModel(testUtils.DataGenerator.forKnex.createPost({
|
||||
id: 'id2',
|
||||
html: '<img href=/content/test.jpf'
|
||||
const ctrlResponse = {
|
||||
data: [
|
||||
postModel(testUtils.DataGenerator.forKnex.createPost({})),
|
||||
postModel(testUtils.DataGenerator.forKnex.createPost({}))
|
||||
],
|
||||
meta: {}
|
||||
};
|
||||
|
||||
}))
|
||||
],
|
||||
meta: {}
|
||||
};
|
||||
serializers.output.pages.all(ctrlResponse, apiConfig, frame);
|
||||
|
||||
serializers.output.posts.all(ctrlResponse, apiConfig, frame);
|
||||
|
||||
frame.response.posts[0].hasOwnProperty('url').should.be.true();
|
||||
frame.response.posts[0].tags[0].hasOwnProperty('url').should.be.true();
|
||||
frame.response.posts[0].authors[0].hasOwnProperty('url').should.be.true();
|
||||
frame.response.posts[1].hasOwnProperty('url').should.be.true();
|
||||
|
||||
urlService.utils.urlFor.callCount.should.eql(4);
|
||||
urlService.utils.urlFor.getCall(0).args.should.eql(['image', {image: 'value'}, true]);
|
||||
urlService.utils.urlFor.getCall(1).args.should.eql(['home', true]);
|
||||
urlService.utils.urlFor.getCall(2).args.should.eql(['image', {image: 'value'}, true]);
|
||||
urlService.utils.urlFor.getCall(3).args.should.eql(['home', true]);
|
||||
|
||||
urlService.utils.makeAbsoluteUrls.callCount.should.eql(2);
|
||||
urlService.utils.makeAbsoluteUrls.getCall(0).args.should.eql([
|
||||
'## markdown',
|
||||
'urlFor',
|
||||
'getUrlByResourceId',
|
||||
{assetsOnly: true}
|
||||
]);
|
||||
|
||||
urlService.utils.makeAbsoluteUrls.getCall(1).args.should.eql([
|
||||
'<img href=/content/test.jpf',
|
||||
'urlFor',
|
||||
'getUrlByResourceId',
|
||||
{assetsOnly: true}
|
||||
]);
|
||||
|
||||
urlService.getUrlByResourceId.callCount.should.eql(4);
|
||||
urlService.getUrlByResourceId.getCall(0).args.should.eql(['id1', {absolute: true}]);
|
||||
urlService.getUrlByResourceId.getCall(1).args.should.eql(['id3', {absolute: true}]);
|
||||
urlService.getUrlByResourceId.getCall(2).args.should.eql(['id4', {absolute: true}]);
|
||||
urlService.getUrlByResourceId.getCall(3).args.should.eql(['id2', {absolute: true}]);
|
||||
});
|
||||
|
||||
it('absolute_urls = true', function () {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
options: {
|
||||
withRelated: ['tags', 'authors'],
|
||||
absolute_urls: true
|
||||
}
|
||||
};
|
||||
|
||||
const ctrlResponse = {
|
||||
data: [
|
||||
postModel(testUtils.DataGenerator.forKnex.createPost({
|
||||
id: 'id2',
|
||||
html: '<img href=/content/test.jpf'
|
||||
}))
|
||||
],
|
||||
meta: {}
|
||||
};
|
||||
|
||||
serializers.output.posts.all(ctrlResponse, apiConfig, frame);
|
||||
urlService.utils.makeAbsoluteUrls.callCount.should.eql(1);
|
||||
urlService.utils.makeAbsoluteUrls.getCall(0).args.should.eql([
|
||||
'<img href=/content/test.jpf',
|
||||
'urlFor',
|
||||
'getUrlByResourceId',
|
||||
{assetsOnly: false}
|
||||
]);
|
||||
});
|
||||
mapper.mapPost.callCount.should.equal(2);
|
||||
mapper.mapPost.getCall(0).args.should.eql([ctrlResponse.data[0], frame]);
|
||||
});
|
||||
});
|
||||
|
|
65
core/test/unit/api/v2/utils/serializers/output/tags_spec.js
Normal file
65
core/test/unit/api/v2/utils/serializers/output/tags_spec.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const testUtils = require('../../../../../../utils');
|
||||
const mapper = require('../../../../../../../server/api/v2/utils/serializers/output/utils/mapper');
|
||||
const serializers = require('../../../../../../../server/api/v2/utils/serializers');
|
||||
|
||||
const sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Unit: v2/utils/serializers/output/tags', () => {
|
||||
let tagModel;
|
||||
|
||||
beforeEach(() => {
|
||||
tagModel = (data) => {
|
||||
return Object.assign(data, {toJSON: sandbox.stub().returns(data)});
|
||||
};
|
||||
|
||||
sandbox.stub(mapper, 'mapTag').returns({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('calls the mapper when single tag present', () => {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
options: {
|
||||
context: {
|
||||
public: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const ctrlResponse = tagModel(testUtils.DataGenerator.forKnex.createTag());
|
||||
|
||||
serializers.output.tags.all(ctrlResponse, apiConfig, frame);
|
||||
|
||||
mapper.mapTag.callCount.should.equal(1);
|
||||
mapper.mapTag.getCall(0).args.should.eql([ctrlResponse, frame]);
|
||||
});
|
||||
|
||||
it('calls the mapper with multiple tags', () => {
|
||||
const apiConfig = {};
|
||||
const frame = {
|
||||
options: {
|
||||
context: {
|
||||
public: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const ctrlResponse = tagModel({
|
||||
data: [
|
||||
testUtils.DataGenerator.forKnex.createTag(),
|
||||
testUtils.DataGenerator.forKnex.createTag()
|
||||
],
|
||||
meta: {}
|
||||
});
|
||||
|
||||
serializers.output.tags.all(ctrlResponse, apiConfig, frame);
|
||||
|
||||
mapper.mapTag.callCount.should.equal(2);
|
||||
mapper.mapTag.getCall(0).args.should.eql([ctrlResponse.data[0], frame]);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const settingsCache = require('../../../../../../../../server/services/settings/cache');
|
||||
const dateUtil = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/date');
|
||||
|
||||
const sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Unit: v2/utils/serializers/output/utils/date', () => {
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('creates date strings in ISO 8601 format with UTC offset', () => {
|
||||
const timezone = 'Europe/Oslo';
|
||||
const testDates = [
|
||||
{in: '2014-01-01T01:28:58.593Z', out: '2014-01-01T02:28:58.593+01:00'},
|
||||
{in:'2014-12-31T23:28:58.123Z', out: '2015-01-01T00:28:58.123+01:00'},
|
||||
{in:'2014-03-01T01:28:58.593Z', out: '2014-03-01T02:28:58.593+01:00'}
|
||||
];
|
||||
sandbox.stub(settingsCache, 'get').returns(timezone);
|
||||
|
||||
testDates.forEach((date) => {
|
||||
dateUtil.format(date.in).should.equal(date.out);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,149 @@
|
|||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const testUtils = require('../../../../../../../utils');
|
||||
const dateUtil = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/date');
|
||||
const urlUtil = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/url');
|
||||
const mapper = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/mapper');
|
||||
|
||||
const sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Unit: v2/utils/serializers/output/utils/mapper', () => {
|
||||
beforeEach(() => {
|
||||
sandbox.stub(dateUtil, 'forPost').returns({});
|
||||
sandbox.stub(dateUtil, 'forTag').returns({});
|
||||
|
||||
sandbox.stub(urlUtil, 'forPost').returns({});
|
||||
sandbox.stub(urlUtil, 'forTag').returns({});
|
||||
sandbox.stub(urlUtil, 'forUser').returns({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('mapPost', () => {
|
||||
let postModel;
|
||||
|
||||
beforeEach(() => {
|
||||
postModel = (data) => {
|
||||
return Object.assign(data, {toJSON: sandbox.stub().returns(data)});
|
||||
};
|
||||
});
|
||||
|
||||
it('calls mapper on relations', () => {
|
||||
const frame = {
|
||||
options: {
|
||||
withRelated: ['tags', 'authors'],
|
||||
context: {
|
||||
public: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const post = postModel(testUtils.DataGenerator.forKnex.createPost({
|
||||
id: 'id1',
|
||||
feature_image: 'value',
|
||||
page: true,
|
||||
tags: [{
|
||||
id: 'id3',
|
||||
feature_image: 'value'
|
||||
}],
|
||||
authors: [{
|
||||
id: 'id4',
|
||||
name: 'Ghosty'
|
||||
}]
|
||||
}));
|
||||
|
||||
mapper.mapPost(post, frame);
|
||||
|
||||
dateUtil.forPost.callCount.should.equal(1);
|
||||
dateUtil.forTag.callCount.should.equal(1);
|
||||
|
||||
urlUtil.forPost.callCount.should.equal(1);
|
||||
urlUtil.forTag.callCount.should.equal(1);
|
||||
urlUtil.forUser.callCount.should.equal(1);
|
||||
|
||||
urlUtil.forTag.getCall(0).args.should.eql(['id3', {id: 'id3', feature_image: 'value'}]);
|
||||
urlUtil.forUser.getCall(0).args.should.eql(['id4', {name: 'Ghosty', id: 'id4'}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapUser', () => {
|
||||
let userModel;
|
||||
|
||||
beforeEach(() => {
|
||||
userModel = (data) => {
|
||||
return Object.assign(data, {toJSON: sandbox.stub().returns(data)});
|
||||
};
|
||||
});
|
||||
|
||||
it('calls utils', () => {
|
||||
const frame = {
|
||||
options: {}
|
||||
};
|
||||
|
||||
const user = userModel(testUtils.DataGenerator.forKnex.createUser({
|
||||
id: 'id1',
|
||||
name: 'Ghosty'
|
||||
}));
|
||||
|
||||
mapper.mapUser(user, frame);
|
||||
|
||||
urlUtil.forUser.callCount.should.equal(1);
|
||||
|
||||
urlUtil.forUser.getCall(0).args.should.eql(['id1', user]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapTag', () => {
|
||||
let tagModel;
|
||||
|
||||
beforeEach(() => {
|
||||
tagModel = (data) => {
|
||||
return Object.assign(data, {toJSON: sandbox.stub().returns(data)});
|
||||
};
|
||||
});
|
||||
|
||||
it('calls utils', () => {
|
||||
const frame = {
|
||||
options: {
|
||||
context: {
|
||||
public: true
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const tag = tagModel(testUtils.DataGenerator.forKnex.createTag({
|
||||
id: 'id3',
|
||||
feature_image: 'value'
|
||||
}));
|
||||
|
||||
mapper.mapTag(tag, frame);
|
||||
|
||||
urlUtil.forTag.callCount.should.equal(1);
|
||||
dateUtil.forTag.callCount.should.equal(1);
|
||||
|
||||
urlUtil.forTag.getCall(0).args.should.eql(['id3', tag]);
|
||||
dateUtil.forTag.getCall(0).args.should.eql([tag]);
|
||||
});
|
||||
|
||||
it('does not call date formatter in private context', () => {
|
||||
const frame = {
|
||||
options: {
|
||||
context: {
|
||||
public: false
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const tag = tagModel(testUtils.DataGenerator.forKnex.createTag({
|
||||
id: 'id3',
|
||||
feature_image: 'value'
|
||||
}));
|
||||
|
||||
mapper.mapTag(tag, frame);
|
||||
|
||||
dateUtil.forTag.callCount.should.equal(0);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,55 @@
|
|||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
const testUtils = require('../../../../../../../utils');
|
||||
const urlService = require('../../../../../../../../server/services/url');
|
||||
const urlUtil = require('../../../../../../../../server/api/v2/utils/serializers/output/utils/url');
|
||||
|
||||
const sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Unit: v2/utils/serializers/output/utils/url', () => {
|
||||
beforeEach(() => {
|
||||
sandbox.stub(urlService, 'getUrlByResourceId').returns('getUrlByResourceId');
|
||||
sandbox.stub(urlService.utils, 'urlFor').returns('urlFor');
|
||||
sandbox.stub(urlService.utils, 'makeAbsoluteUrls').returns({html: sandbox.stub()});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('Ensure calls url service', () => {
|
||||
let pageModel;
|
||||
|
||||
beforeEach(() => {
|
||||
pageModel = (data) => {
|
||||
return Object.assign(data, {toJSON: sandbox.stub().returns(data)});
|
||||
};
|
||||
});
|
||||
|
||||
it('meta & models & relations', () => {
|
||||
const post = pageModel(testUtils.DataGenerator.forKnex.createPost({
|
||||
id: 'id1',
|
||||
feature_image: 'value',
|
||||
}));
|
||||
|
||||
urlUtil.forPost(post.id, post, {});
|
||||
|
||||
post.hasOwnProperty('url').should.be.true();
|
||||
|
||||
urlService.utils.urlFor.callCount.should.eql(2);
|
||||
urlService.utils.urlFor.getCall(0).args.should.eql(['image', {image: 'value'}, true]);
|
||||
urlService.utils.urlFor.getCall(1).args.should.eql(['home', true]);
|
||||
|
||||
urlService.utils.makeAbsoluteUrls.callCount.should.eql(1);
|
||||
urlService.utils.makeAbsoluteUrls.getCall(0).args.should.eql([
|
||||
'## markdown',
|
||||
'urlFor',
|
||||
'getUrlByResourceId',
|
||||
{assetsOnly: true}
|
||||
]);
|
||||
|
||||
urlService.getUrlByResourceId.callCount.should.eql(1);
|
||||
urlService.getUrlByResourceId.getCall(0).args.should.eql(['id1', {absolute: true}]);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue