paradigm-core
Version:
Paradigm Core Modules
706 lines (596 loc) • 20.4 kB
JavaScript
const moment = require('moment')
const {
Migrations,
OrganizationsPlugin,
ApplicationsPlugin,
UsersPlugin,
DigitalAssetsPlugin,
TestHelpers: {MockHTTPServer},
} = require('structure-core')
const DocumentsPlugin = require('../../../documents')
const pluginsList = require('../helpers/plugins')
const AppleNewsArticleModel = require('../../models/apple-news-article')
const AppleNewsAPI = require('../../lib/apple-news-api')
const server = new MockHTTPServer(pluginsList)
const orgTestApi = new OrganizationsPlugin.TestAPI(server)
const appTestApi = new ApplicationsPlugin.TestAPI(server)
const userTestApi = new UsersPlugin.TestAPI(server)
const digitalAssetTestApi = new DigitalAssetsPlugin.TestAPI(server)
const docTestApi = new DocumentsPlugin.TestAPIDocuments(server)
function formatDateString(dateString) {
return new Date(dateString).toLocaleDateString(
'en-us',
{year: 'numeric', month: 'long', day: 'numeric'}
)
}
function formatDate(date) {
return moment(date).utc().format('YYYY-MM-DDTHH:mm:ss[Z]')
}
/** @test {AppleNewsArticleModel} */
describe('AppleNewsArticleModel', function() {
before(function() {
this.timeout(10000)
this.migration = new Migrations({
db: 'test',
items: {tables: [{
action: 'create',
table: 'digital_assets',
indexes: [
'applicationId',
'updatedAt'
]
}]},
plugins: pluginsList
})
this.sandbox = sinon.sandbox.create()
this.createArticleSpy = this.sandbox.spy()
this.updateArticleSpy = this.sandbox.spy()
this.deleteArticleSpy = this.sandbox.spy()
this.readArticleSpy = this.sandbox.spy()
this.sandbox.stub(AppleNewsAPI.prototype, 'createArticle').callsFake((...args) => {
this.createArticleSpy(...args)
return {id: 12345}
}) // surely there's a better way to do this :|
this.sandbox.stub(AppleNewsAPI.prototype, 'updateArticle').callsFake((...args) => {
this.updateArticleSpy(...args)
return {id: 12345}
})
this.sandbox.stub(AppleNewsAPI.prototype, 'deleteArticle').callsFake((...args) => {
this.deleteArticleSpy(...args)
return
})
this.sandbox.stub(AppleNewsAPI.prototype, 'readArticle').callsFake((...args) => {
this.readArticleSpy(...args)
return {revision: 'AAAAAAAAAAAAAAAAAAAACA=='}
})
return this.migration.process()
})
beforeEach(async function() {
const orgRes = await orgTestApi.create({
title: 'Forbidden Children'
})
this.orgId = orgRes.body.pkg.id
const appRes = await appTestApi.create(this.orgId, {
desc: '',
title: 'App 45',
host: 'app45.com',
appleNewsChannelId: process.env.APPLE_NEWS_CHANNEL,
appleNewsApiId: process.env.APPLE_NEWS_KEY,
appleNewsApiSecret: process.env.APPLE_NEWS_SECRET
})
this.appId = appRes.body.pkg.id
const userRes = await userTestApi.create(this.orgId, this.appId, {
organizationId: this.orgId,
username: 'jsmith',
firstName: 'John',
lastName: 'Smith',
email: 'jsmith@example.com',
password: 'c4ntf1ndmyc4v3br0',
timezone: 'Europe/Madrid'
})
this.user = userRes.body.pkg
})
afterEach(function() {
this.createArticleSpy.resetHistory()
this.updateArticleSpy.resetHistory()
this.deleteArticleSpy.resetHistory()
this.readArticleSpy.resetHistory()
return this.migration.purge()
})
after(function() {
this.sandbox.restore()
})
describe('basic article', function() {
beforeEach(async function() {
const docRes = await docTestApi.create(this.orgId, this.appId, {
title: 'Basic Article',
slug: 'basic-article',
fields: [
{
type: 'text',
props: {
value: '<p>Text 1</p>'
}
},
{
type: 'text',
props: {
value: '<p>Text 2</p>'
}
}
],
categoryIds: [],
status: 'published',
organizationId: this.orgId,
userId: this.user.id
})
this.doc = docRes.body.pkg
})
/** @test {AppleNewsArticleModel#create} */
it('should create a basic article', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
expect(this.createArticleSpy).to.have.been.calledOnce
expect(this.updateArticleSpy).to.not.have.been.calledOnce
expect(this.deleteArticleSpy).to.not.have.been.calledOnce
expect(res.articleId).to.equal(12345)
expect(res.articleJson.article.version).to.equal('1.0')
expect(res.articleJson.article.title).to.equal(this.doc.title)
expect(res.articleJson.article.identifier).to.equal(this.doc.slug)
expect(res.articleJson.article.language).to.equal('en')
expect(res.articleJson.article.metadata.authors).to.deep.equal([`${this.user.firstName} ${this.user.lastName}`])
expect(res.articleJson.article.metadata.dateModified).to.equal(formatDate(this.doc.updatedAt))
expect(res.articleJson.article.metadata.datePublished).to.equal(formatDate(this.doc.publishedAt))
expect(res.articleJson.article.metadata.dateCreated).to.equal(formatDate(this.doc.publishedAt))
expect(res.articleJson.article.components).to.deep.equal([
{
role: 'header',
layout: 'headerLayout',
style: 'headerStyle',
components: [
{
role: 'title',
layout: 'titleLayout',
text: this.doc.title
},
{
text: `By ${this.user.firstName} ${this.user.lastName} ${formatDateString(this.doc.publishedAt)}`,
additions: [],
inlineTextStyles: [],
role: 'byline',
layout: 'bylineLayout'
}
]
},
{
text: 'Text 1\n',
additions: [],
inlineTextStyles: [],
role: 'body',
layout: 'bodyLayout'
},
{
text: 'Text 2\n',
additions: [],
inlineTextStyles: [],
role: 'body',
layout: 'bodyLayout'
}
])
})
/** @test {AppleNewsArticleModel#update} */
it('should sync revision of a basic article', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
const res2 = await appleNewsArticleModel.syncArticleRevsion(res)
expect(res2.articleRevision).to.equal('AAAAAAAAAAAAAAAAAAAACA==')
expect(this.readArticleSpy).to.have.been.calledOnce
expect(this.readArticleSpy.args[0][0]).to.equal(res.articleId)
})
/** @test {AppleNewsArticleModel#update} */
it('should update a basic article', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
const docRes = await docTestApi.update(this.orgId, this.appId, this.doc.id, {
title: 'Basic Article Updated',
slug: 'basic-article-updated'
})
const updatedDoc = docRes.body.pkg
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
expect(this.createArticleSpy).to.have.been.calledOnce
expect(this.createArticleSpy.args[0][0].title).to.equal(this.doc.title)
expect(this.deleteArticleSpy).to.not.have.been.calledOnce
expect(this.updateArticleSpy).to.have.been.calledOnce
expect(this.updateArticleSpy.args[0][0]).to.equal(res.articleId)
expect(this.updateArticleSpy.args[0][2].title).to.equal(updatedDoc.title)
expect(this.updateArticleSpy.args[0][2].identifier).to.equal(updatedDoc.slug)
})
/** @test {AppleNewsArticleModel#delete} */
it('should delete a basic article', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
await appleNewsArticleModel.deleteForDocument(this.doc.id)
expect(this.createArticleSpy).to.have.been.calledOnce
expect(this.updateArticleSpy).to.not.have.been.calledOnce
expect(this.deleteArticleSpy).to.have.been.calledOnce
expect(this.deleteArticleSpy.args[0][0]).to.equal(res.articleId)
})
})
describe('article with markup', function() {
beforeEach(async function() {
const docRes = await docTestApi.create(this.orgId, this.appId, {
title: 'Article With Markup',
slug: 'article-with-markup',
fields: [
{
type: 'text',
props: {
value: '<p>Plain <em>Italic</em> <strong>Bold</strong> <a href="https://www.example.com">Link</a></p>'
}
},
],
categoryIds: [],
status: 'published',
organizationId: this.orgId,
userId: this.user.id
})
this.doc = docRes.body.pkg
})
/** @test {AppleNewsArticleModel#create} */
it('should create a article with markup', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
expect(this.createArticleSpy).to.have.been.calledOnce
expect(res.articleId).to.equal(12345)
expect(res.articleJson.article.components).to.deep.equal([
{
role: 'header',
layout: 'headerLayout',
style: 'headerStyle',
components: [
{
role: 'title',
layout: 'titleLayout',
text: this.doc.title
},
{
text: `By ${this.user.firstName} ${this.user.lastName} ${formatDateString(this.doc.publishedAt)}`,
additions: [],
inlineTextStyles: [],
role: 'byline',
layout: 'bylineLayout'
}
]
},
{
text: 'Plain Italic Bold Link\n',
additions: [{
type: 'link',
rangeStart: 18,
rangeLength: 4,
URL: 'https://www.example.com'
}],
inlineTextStyles: [
{rangeStart: 6, rangeLength: 6, textStyle: 'bodyItalicStyle'},
{rangeStart: 13, rangeLength: 4, textStyle: 'bodyBoldStyle'},
{rangeStart: 18, rangeLength: 4, textStyle: 'bodyLinkTextStyle'}
],
role: 'body',
layout: 'bodyLayout'
}
])
})
})
describe('article with twitter embed', function() {
beforeEach(async function() {
const docRes = await docTestApi.create(this.orgId, this.appId, {
title: 'Article With Excerpt',
slug: 'article-with-excerpt',
excerpt: '<p>Excerpt</p>',
fields: [
{
type: 'text',
props: {
value: '<p>Text 1</p>'
}
}
],
categoryIds: [],
status: 'published',
organizationId: this.orgId,
userId: this.user.id
})
this.doc = docRes.body.pkg
})
/** @test {AppleNewsArticleModel#create} */
it('should create an article with excerpt', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
expect(this.createArticleSpy).to.have.been.calledOnce
expect(res.articleId).to.equal(12345)
expect(res.articleJson.article.metadata.excerpt).to.equal('Excerpt')
expect(res.articleJson.article.components).to.deep.equal([
{
role: 'header',
layout: 'headerLayout',
style: 'headerStyle',
components: [
{
role: 'title',
layout: 'titleLayout',
text: this.doc.title
},
{
text: `By ${this.user.firstName} ${this.user.lastName} ${formatDateString(this.doc.publishedAt)}`,
additions: [],
inlineTextStyles: [],
role: 'byline',
layout: 'bylineLayout'
}
]
},
{
text: 'Excerpt\n',
additions: [],
inlineTextStyles: [],
role: 'body',
layout: 'bodyLayout'
},
{
text: 'Text 1\n',
additions: [],
inlineTextStyles: [],
role: 'body',
layout: 'bodyLayout'
},
])
})
})
describe('article with featured image', function() {
beforeEach(async function() {
const daRes = await digitalAssetTestApi.getByUrl(
this.orgId,
this.appId,
'https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Cat_poster_1.jpg/1280px-Cat_poster_1.jpg'
)
this.da = daRes.body.pkg
const docRes = await docTestApi.create(this.orgId, this.appId, {
title: 'Article With Featured Image',
slug: 'article-with-featured-image',
featuredImageId: this.da.id,
fields: [
{
type: 'text',
props: {
value: '<p>Text 1</p>'
}
},
{
type: 'text',
props: {
value: '<p>Text 2</p>'
}
}
],
categoryIds: [],
status: 'published',
organizationId: this.orgId,
userId: this.user.id
})
this.doc = docRes.body.pkg
})
/** @test {AppleNewsArticleModel#create} */
it('should create an article with thumbnail image', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
expect(this.createArticleSpy).to.have.been.calledOnce
expect(res.articleId).to.equal(12345)
expect(res.articleJson.article.metadata.thumbnailURL).to.equal('bundle://image-0.jpg')
expect(res.articleJson.bundlesToUrls['image-0.jpg']).to.equal(`http:${this.da.url}`)
})
})
describe('article with image embed', function() {
beforeEach(async function() {
const daRes = await digitalAssetTestApi.getByUrl(
this.orgId,
this.appId,
'https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Cat_poster_1.jpg/1280px-Cat_poster_1.jpg'
)
this.da = daRes.body.pkg
const docRes = await docTestApi.create(this.orgId, this.appId, {
title: 'Article With Image Embed',
slug: 'article-with-image-embed',
fields: [
{
type: 'text',
props: {
value: '<p>Text 1</p>'
}
},
{
type: 'embed',
props: {
digitalAssetId: this.da.id
}
},
],
categoryIds: [],
status: 'published',
organizationId: this.orgId,
userId: this.user.id
})
this.doc = docRes.body.pkg
})
/** @test {AppleNewsArticleModel#create} */
it('should create an article with image embed', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
expect(this.createArticleSpy).to.have.been.calledOnce
expect(res.articleId).to.equal(12345)
expect(res.articleJson.article.components).to.deep.equal([
{
role: 'header',
layout: 'headerLayout',
style: 'headerStyle',
components: [
{
role: 'title',
layout: 'titleLayout',
text: this.doc.title
},
{
text: `By ${this.user.firstName} ${this.user.lastName} ${formatDateString(this.doc.publishedAt)}`,
additions: [],
inlineTextStyles: [],
role: 'byline',
layout: 'bylineLayout'
}
]
},
{
text: 'Text 1\n',
additions: [],
inlineTextStyles: [],
role: 'body',
layout: 'bodyLayout'
},
{
role: 'container',
components: [{
role: 'photo',
URL: 'bundle://image-0.jpg',
style: 'embedMediaStyle',
layout: 'embedMediaLayout'
}],
layout: 'embedLayout',
style: 'embedStyle'
}
])
expect(res.articleJson.bundlesToUrls['image-0.jpg']).to.equal(`http:${this.da.url}`)
})
})
describe('article with twitter embed', function() {
beforeEach(async function() {
const daRes = await digitalAssetTestApi.getByUrl(
this.orgId,
this.appId,
'https://twitter.com/Interior/status/463440424141459456'
)
this.da = daRes.body.pkg
const docRes = await docTestApi.create(this.orgId, this.appId, {
title: 'Article With Twitter Embed',
slug: 'article-with-twitter-embed',
fields: [
{
type: 'text',
props: {
value: '<p>Text 1</p>'
}
},
{
type: 'embed',
props: {
digitalAssetId: this.da.id
}
},
],
categoryIds: [],
status: 'published',
organizationId: this.orgId,
userId: this.user.id
})
this.doc = docRes.body.pkg
})
/** @test {AppleNewsArticleModel#create} */
it('should create an article with twitter embed', async function() {
this.timeout(30000)
const appleNewsArticleModel = new AppleNewsArticleModel({
organizationId: this.orgId,
applicationId: this.appId,
logger: this.logger
})
const res = await appleNewsArticleModel.createOrUpdateForDocument(this.doc.id)
expect(this.createArticleSpy).to.have.been.calledOnce
expect(res.articleId).to.equal(12345)
expect(res.articleJson.article.components).to.deep.equal([
{
role: 'header',
layout: 'headerLayout',
style: 'headerStyle',
components: [
{
role: 'title',
layout: 'titleLayout',
text: this.doc.title
},
{
text: `By ${this.user.firstName} ${this.user.lastName} ${formatDateString(this.doc.publishedAt)}`,
additions: [],
inlineTextStyles: [],
role: 'byline',
layout: 'bylineLayout'
}
]
},
{
text: 'Text 1\n',
additions: [],
inlineTextStyles: [],
role: 'body',
layout: 'bodyLayout'
},
{
role: 'container',
components: [{
role: 'tweet',
URL: "https://twitter.com/Interior/status/463440424141459456",
style: 'embedMediaStyle',
layout: 'embedMediaLayout'
}],
layout: 'embedLayout',
style: 'embedStyle'
}
])
})
})
})