UNPKG

paradigm-core

Version:
706 lines (596 loc) 20.4 kB
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' } ]) }) }) })