/* eslint-disable camelcase */ import EmberObject from '@ember/object'; import RSVP from 'rsvp'; import boundOneWay from 'ghost-admin/utils/bound-one-way'; import {describe, it} from 'mocha'; import {run} from '@ember/runloop'; import {setupComponentTest} from 'ember-mocha'; function K() { return this; } // TODO: convert to integration tests describe.skip('Unit: Component: post-settings-menu', function () { setupComponentTest('gh-post-settings-menu', { needs: ['service:notifications', 'service:slug-generator', 'service:settings'] }); it('slugValue is one-way bound to post.slug', function () { let component = this.subject({ post: EmberObject.create({ slug: 'a-slug' }) }); expect(component.get('post.slug')).to.equal('a-slug'); expect(component.get('slugValue')).to.equal('a-slug'); run(function () { component.set('post.slug', 'changed-slug'); expect(component.get('slugValue')).to.equal('changed-slug'); }); run(function () { component.set('slugValue', 'changed-directly'); expect(component.get('post.slug')).to.equal('changed-slug'); expect(component.get('slugValue')).to.equal('changed-directly'); }); run(function () { // test that the one-way binding is still in place component.set('post.slug', 'should-update'); expect(component.get('slugValue')).to.equal('should-update'); }); }); it('metaTitleScratch is one-way bound to post.metaTitle', function () { let component = this.subject({ post: EmberObject.extend({ metaTitle: 'a title', metaTitleScratch: boundOneWay('metaTitle') }).create() }); expect(component.get('post.metaTitle')).to.equal('a title'); expect(component.get('metaTitleScratch')).to.equal('a title'); run(function () { component.set('post.metaTitle', 'a different title'); expect(component.get('metaTitleScratch')).to.equal('a different title'); }); run(function () { component.set('metaTitleScratch', 'changed directly'); expect(component.get('post.metaTitle')).to.equal('a different title'); expect(component.get('post.metaTitleScratch')).to.equal('changed directly'); }); run(function () { // test that the one-way binding is still in place component.set('post.metaTitle', 'should update'); expect(component.get('metaTitleScratch')).to.equal('should update'); }); }); it('metaDescriptionScratch is one-way bound to post.metaDescription', function () { let component = this.subject({ post: EmberObject.extend({ metaDescription: 'a description', metaDescriptionScratch: boundOneWay('metaDescription') }).create() }); expect(component.get('post.metaDescription')).to.equal('a description'); expect(component.get('metaDescriptionScratch')).to.equal('a description'); run(function () { component.set('post.metaDescription', 'a different description'); expect(component.get('metaDescriptionScratch')).to.equal('a different description'); }); run(function () { component.set('metaDescriptionScratch', 'changed directly'); expect(component.get('post.metaDescription')).to.equal('a different description'); expect(component.get('metaDescriptionScratch')).to.equal('changed directly'); }); run(function () { // test that the one-way binding is still in place component.set('post.metaDescription', 'should update'); expect(component.get('metaDescriptionScratch')).to.equal('should update'); }); }); describe('seoTitle', function () { it('should be the metaTitle if one exists', function () { let component = this.subject({ post: EmberObject.extend({ titleScratch: 'should not be used', metaTitle: 'a meta-title', metaTitleScratch: boundOneWay('metaTitle') }).create() }); expect(component.get('seoTitle')).to.equal('a meta-title'); }); it('should default to the title if an explicit meta-title does not exist', function () { let component = this.subject({ post: EmberObject.create({ titleScratch: 'should be the meta-title' }) }); expect(component.get('seoTitle')).to.equal('should be the meta-title'); }); it('should be the metaTitle if both title and metaTitle exist', function () { let component = this.subject({ post: EmberObject.extend({ titleScratch: 'a title', metaTitle: 'a meta-title', metaTitleScratch: boundOneWay('metaTitle') }).create() }); expect(component.get('seoTitle')).to.equal('a meta-title'); }); it('should revert to the title if explicit metaTitle is removed', function () { let component = this.subject({ post: EmberObject.extend({ titleScratch: 'a title', metaTitle: 'a meta-title', metaTitleScratch: boundOneWay('metaTitle') }).create() }); expect(component.get('seoTitle')).to.equal('a meta-title'); run(function () { component.set('post.metaTitle', ''); expect(component.get('seoTitle')).to.equal('a title'); }); }); it('should truncate to 70 characters with an appended ellipsis', function () { let longTitle = new Array(100).join('a'); let component = this.subject({ post: EmberObject.create() }); expect(longTitle.length).to.equal(99); run(function () { let expected = `${longTitle.substr(0, 70)}…`; component.set('metaTitleScratch', longTitle); expect(component.get('seoTitle').toString().length).to.equal(78); expect(component.get('seoTitle').toString()).to.equal(expected); }); }); }); describe('seoDescription', function () { it('should be the metaDescription if one exists', function () { let component = this.subject({ post: EmberObject.extend({ metaDescription: 'a description', metaDescriptionScratch: boundOneWay('metaDescription') }).create() }); expect(component.get('seoDescription')).to.equal('a description'); }); it('should be generated from the rendered mobiledoc if not explicitly set', function () { let component = this.subject({ post: EmberObject.extend({ metaDescription: null, metaDescriptionScratch: boundOneWay('metaDescription'), author: RSVP.resolve(), init() { this._super(...arguments); this.scratch = { cards: [ ['markdown-card', { markdown: '# This is a test ' }] ] }; } }).create() }); expect(component.get('seoDescription')).to.equal('This is a test'); }); it('should truncate to 156 characters with an appended ellipsis', function () { let longDescription = new Array(200).join('a'); let component = this.subject({ post: EmberObject.create() }); expect(longDescription.length).to.equal(199); run(function () { let expected = `${longDescription.substr(0, 156)}…`; component.set('metaDescriptionScratch', longDescription); expect(component.get('seoDescription').toString().length).to.equal(164); expect(component.get('seoDescription').toString()).to.equal(expected); }); }); }); describe('seoURL', function () { it('should be the URL of the blog if no post slug exists', function () { let component = this.subject({ config: EmberObject.create({blogUrl: 'http://my-ghost-blog.com'}), post: EmberObject.create() }); expect(component.get('seoURL')).to.equal('http://my-ghost-blog.com/'); }); it('should be the URL of the blog plus the post slug', function () { let component = this.subject({ config: EmberObject.create({blogUrl: 'http://my-ghost-blog.com'}), post: EmberObject.create({slug: 'post-slug'}) }); expect(component.get('seoURL')).to.equal('http://my-ghost-blog.com/post-slug/'); }); it('should update when the post slug changes', function () { let component = this.subject({ config: EmberObject.create({blogUrl: 'http://my-ghost-blog.com'}), post: EmberObject.create({slug: 'post-slug'}) }); expect(component.get('seoURL')).to.equal('http://my-ghost-blog.com/post-slug/'); run(function () { component.set('post.slug', 'changed-slug'); expect(component.get('seoURL')).to.equal('http://my-ghost-blog.com/changed-slug/'); }); }); it('should truncate a long URL to 70 characters with an appended ellipsis', function () { let blogURL = 'http://my-ghost-blog.com'; let longSlug = new Array(75).join('a'); let component = this.subject({ config: EmberObject.create({blogUrl: blogURL}), post: EmberObject.create({slug: longSlug}) }); let expected; expect(longSlug.length).to.equal(74); expected = `${blogURL}/${longSlug}/`; expected = `${expected.substr(0, 70)}…`; expect(component.get('seoURL').toString().length).to.equal(78); expect(component.get('seoURL').toString()).to.equal(expected); }); }); describe('togglePage', function () { it('should toggle the page property', function () { let component = this.subject({ post: EmberObject.create({ page: false, isNew: true }) }); expect(component.get('post.page')).to.not.be.ok; run(function () { component.send('togglePage'); expect(component.get('post.page')).to.be.ok; }); }); it('should not save the post if it is still new', function () { let component = this.subject({ post: EmberObject.create({ page: false, isNew: true, save() { this.incrementProperty('saved'); return RSVP.resolve(); } }) }); run(function () { component.send('togglePage'); expect(component.get('post.page')).to.be.ok; expect(component.get('post.saved')).to.not.be.ok; }); }); it('should save the post if it is not new', function () { let component = this.subject({ post: EmberObject.create({ page: false, isNew: false, save() { this.incrementProperty('saved'); return RSVP.resolve(); } }) }); run(function () { component.send('togglePage'); expect(component.get('post.page')).to.be.ok; expect(component.get('post.saved')).to.equal(1); }); }); }); describe('toggleFeatured', function () { it('should toggle the featured property', function () { let component = this.subject({ post: EmberObject.create({ featured: false, isNew: true }) }); run(function () { component.send('toggleFeatured'); expect(component.get('post.featured')).to.be.ok; }); }); it('should not save the post if it is still new', function () { let component = this.subject({ post: EmberObject.create({ featured: false, isNew: true, save() { this.incrementProperty('saved'); return RSVP.resolve(); } }) }); run(function () { component.send('toggleFeatured'); expect(component.get('post.featured')).to.be.ok; expect(component.get('post.saved')).to.not.be.ok; }); }); it('should save the post if it is not new', function () { let component = this.subject({ post: EmberObject.create({ featured: false, isNew: false, save() { this.incrementProperty('saved'); return RSVP.resolve(); } }) }); run(function () { component.send('toggleFeatured'); expect(component.get('post.featured')).to.be.ok; expect(component.get('post.saved')).to.equal(1); }); }); }); describe('updateSlug', function () { it('should reset slugValue to the previous slug when the new slug is blank or unchanged', function () { let component = this.subject({ post: EmberObject.create({ slug: 'slug' }) }); run(function () { // unchanged component.set('slugValue', 'slug'); component.send('updateSlug', component.get('slugValue')); expect(component.get('post.slug')).to.equal('slug'); expect(component.get('slugValue')).to.equal('slug'); }); run(function () { // unchanged after trim component.set('slugValue', 'slug '); component.send('updateSlug', component.get('slugValue')); expect(component.get('post.slug')).to.equal('slug'); expect(component.get('slugValue')).to.equal('slug'); }); run(function () { // blank component.set('slugValue', ''); component.send('updateSlug', component.get('slugValue')); expect(component.get('post.slug')).to.equal('slug'); expect(component.get('slugValue')).to.equal('slug'); }); }); it('should not set a new slug if the server-generated slug matches existing slug', function (done) { let component = this.subject({ slugGenerator: EmberObject.create({ generateSlug(slugType, str) { let promise = RSVP.resolve(str.split('#')[0]); this.set('lastPromise', promise); return promise; } }), post: EmberObject.create({ slug: 'whatever' }) }); run(function () { component.set('slugValue', 'whatever#slug'); component.send('updateSlug', component.get('slugValue')); RSVP.resolve(component.get('lastPromise')).then(function () { expect(component.get('post.slug')).to.equal('whatever'); done(); }).catch(done); }); }); it('should not set a new slug if the only change is to the appended increment value', function (done) { let component = this.subject({ slugGenerator: EmberObject.create({ generateSlug(slugType, str) { let sanitizedStr = str.replace(/[^a-zA-Z]/g, ''); let promise = RSVP.resolve(`${sanitizedStr}-2`); this.set('lastPromise', promise); return promise; } }), post: EmberObject.create({ slug: 'whatever' }) }); run(function () { component.set('slugValue', 'whatever!'); component.send('updateSlug', component.get('slugValue')); RSVP.resolve(component.get('lastPromise')).then(function () { expect(component.get('post.slug')).to.equal('whatever'); done(); }).catch(done); }); }); it('should set the slug if the new slug is different', function (done) { let component = this.subject({ slugGenerator: EmberObject.create({ generateSlug(slugType, str) { let promise = RSVP.resolve(str); this.set('lastPromise', promise); return promise; } }), post: EmberObject.create({ slug: 'whatever', save: K }) }); run(function () { component.set('slugValue', 'changed'); component.send('updateSlug', component.get('slugValue')); RSVP.resolve(component.get('lastPromise')).then(function () { expect(component.get('post.slug')).to.equal('changed'); done(); }).catch(done); }); }); it('should save the post when the slug changes and the post is not new', function (done) { let component = this.subject({ slugGenerator: EmberObject.create({ generateSlug(slugType, str) { let promise = RSVP.resolve(str); this.set('lastPromise', promise); return promise; } }), post: EmberObject.create({ slug: 'whatever', saved: 0, isNew: false, save() { this.incrementProperty('saved'); } }) }); run(function () { component.set('slugValue', 'changed'); component.send('updateSlug', component.get('slugValue')); RSVP.resolve(component.get('lastPromise')).then(function () { expect(component.get('post.slug')).to.equal('changed'); expect(component.get('post.saved')).to.equal(1); done(); }).catch(done); }); }); it('should not save the post when the slug changes and the post is new', function (done) { let component = this.subject({ slugGenerator: EmberObject.create({ generateSlug(slugType, str) { let promise = RSVP.resolve(str); this.set('lastPromise', promise); return promise; } }), post: EmberObject.create({ slug: 'whatever', saved: 0, isNew: true, save() { this.incrementProperty('saved'); } }) }); run(function () { component.set('slugValue', 'changed'); component.send('updateSlug', component.get('slugValue')); RSVP.resolve(component.get('lastPromise')).then(function () { expect(component.get('post.slug')).to.equal('changed'); expect(component.get('post.saved')).to.equal(0); done(); }).catch(done); }); }); }); });