mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-19 16:42:17 +03:00
ed843718b2
closes https://github.com/TryGhost/Ghost/issues/8122 - because the PSM is now a component, some of the component lifecycle hooks can be employed to load things
537 lines
24 KiB
JavaScript
537 lines
24 KiB
JavaScript
/* jshint expr:true */
|
|
import {
|
|
describe,
|
|
it,
|
|
beforeEach,
|
|
afterEach
|
|
} from 'mocha';
|
|
import {expect} from 'chai';
|
|
import startApp from '../helpers/start-app';
|
|
import destroyApp from '../helpers/destroy-app';
|
|
import {invalidateSession, authenticateSession} from 'ghost-admin/tests/helpers/ember-simple-auth';
|
|
import Mirage from 'ember-cli-mirage';
|
|
import sinon from 'sinon';
|
|
import testSelector from 'ember-test-selectors';
|
|
|
|
describe('Acceptance: Editor', function() {
|
|
let application;
|
|
|
|
beforeEach(function() {
|
|
application = startApp();
|
|
});
|
|
|
|
afterEach(function() {
|
|
destroyApp(application);
|
|
});
|
|
|
|
it('redirects to signin when not authenticated', function () {
|
|
server.create('user'); // necessray for post-author association
|
|
server.create('post');
|
|
|
|
invalidateSession(application);
|
|
visit('/editor/1');
|
|
|
|
andThen(function() {
|
|
expect(currentURL(), 'currentURL').to.equal('/signin');
|
|
});
|
|
});
|
|
|
|
it('does not redirect to team page when authenticated as author', function () {
|
|
let role = server.create('role', {name: 'Author'});
|
|
server.create('user', {roles: [role], slug: 'test-user'});
|
|
server.create('post');
|
|
|
|
authenticateSession(application);
|
|
visit('/editor/1');
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL').to.equal('/editor/1');
|
|
});
|
|
});
|
|
|
|
it('does not redirect to team page when authenticated as editor', function () {
|
|
let role = server.create('role', {name: 'Editor'});
|
|
server.create('user', {roles: [role], slug: 'test-user'});
|
|
server.create('post');
|
|
|
|
authenticateSession(application);
|
|
visit('/editor/1');
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL').to.equal('/editor/1');
|
|
});
|
|
});
|
|
|
|
it('displays 404 when post does not exist', function () {
|
|
let role = server.create('role', {name: 'Editor'});
|
|
server.create('user', {roles: [role], slug: 'test-user'});
|
|
|
|
authenticateSession(application);
|
|
visit('/editor/1');
|
|
|
|
andThen(() => {
|
|
expect(currentPath()).to.equal('error404');
|
|
expect(currentURL()).to.equal('/editor/1');
|
|
});
|
|
});
|
|
|
|
describe('when logged in', function () {
|
|
beforeEach(function () {
|
|
let role = server.create('role', {name: 'Administrator'});
|
|
server.create('user', {roles: [role]});
|
|
server.loadFixtures('settings');
|
|
|
|
return authenticateSession(application);
|
|
});
|
|
|
|
it('renders the editor correctly, PSM Publish Date and Save Button', function () {
|
|
server.createList('post', 2);
|
|
let plusTenMinPacific = moment().tz('Pacific/Kwajalein').add(10, 'minutes').format('DD MMM YY @ HH:mm').toString();
|
|
let plusTwoMinPacific = moment().tz('Pacific/Kwajalein').add(2, 'minutes').format('DD MMM YY @ HH:mm').toString();
|
|
|
|
// post id 1 is a draft, checking for draft behaviour now
|
|
visit('/editor/1');
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL')
|
|
.to.equal('/editor/1');
|
|
});
|
|
|
|
// should error, if the date input is in a wrong format
|
|
fillIn('input[name="post-setting-date"]', 'testdate');
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
|
|
andThen(() => {
|
|
expect(find('.ember-view.response').text().trim(), 'inline error response for invalid date')
|
|
.to.equal('Published Date must be a valid date with format: DD MMM YY @ HH:mm (e.g. 6 Dec 14 @ 15:00)');
|
|
});
|
|
|
|
// saves the post with the new date
|
|
fillIn('input[name="post-setting-date"]', '10 May 16 @ 10:00');
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
// saving
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(find('input[name="post-setting-date"]').val(), 'date after saving')
|
|
.to.equal('10 May 16 @ 10:00');
|
|
});
|
|
|
|
// should not do anything if the input date is not different
|
|
fillIn('input[name="post-setting-date"]', '10 May 16 @ 10:00');
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
|
|
andThen(() => {
|
|
expect(find('input[name="post-setting-date"]').val(), 'date didn\'t change')
|
|
.to.equal('10 May 16 @ 10:00');
|
|
});
|
|
|
|
// checking the flow of the saving button for a draft
|
|
andThen(() => {
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'no red button expected')
|
|
.to.be.false;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button')
|
|
.to.equal('Save Draft');
|
|
expect(find('.post-save-draft').hasClass('active'), 'highlights the default active button state for a draft')
|
|
.to.be.true;
|
|
});
|
|
|
|
// click on publish now
|
|
click('.post-save-publish a');
|
|
|
|
andThen(() => {
|
|
expect(find('.post-save-publish').hasClass('active'), 'highlights the selected active button state')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'red button to change from draft to published')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button after click on \'publish now\'')
|
|
.to.equal('Publish Now');
|
|
});
|
|
|
|
// Publish the post
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button after publishing')
|
|
.to.equal('Update Post');
|
|
expect(find('.post-save-publish').hasClass('active'), 'highlights the default active button state for a published post')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'no red button expected')
|
|
.to.be.false;
|
|
});
|
|
|
|
// post id 2 is a published post, checking for published post behaviour now
|
|
visit('/editor/2');
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL').to.equal('/editor/2');
|
|
expect(find('input[name="post-setting-date"]').val()).to.equal('19 Dec 15 @ 16:25');
|
|
});
|
|
|
|
// should reset the date if the input field is blank
|
|
fillIn('input[name="post-setting-date"]', '');
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
|
|
andThen(() => {
|
|
expect(find('input[name="post-setting-date"]').val(), 'empty date input')
|
|
.to.equal('');
|
|
});
|
|
|
|
// saving
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(find('input[name="post-setting-date"]').val(), 'date value restored')
|
|
.to.equal('19 Dec 15 @ 16:25');
|
|
});
|
|
|
|
// saves the post with a new date
|
|
fillIn('input[name="post-setting-date"]', '10 May 16 @ 10:00');
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
// saving
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(find('input[name="post-setting-date"]').val(), 'new date after saving')
|
|
.to.equal('10 May 16 @ 10:00');
|
|
});
|
|
|
|
// go to settings to change the timezone
|
|
visit('/settings/general');
|
|
click(testSelector('toggle-timezone'));
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL for settings')
|
|
.to.equal('/settings/general');
|
|
expect(find('#activeTimezone option:selected').text().trim(), 'default timezone')
|
|
.to.equal('(GMT) UTC');
|
|
// select a new timezone
|
|
find('#activeTimezone option[value="Pacific/Kwajalein"]').prop('selected', true);
|
|
});
|
|
|
|
triggerEvent('#activeTimezone', 'change');
|
|
// save the settings
|
|
click('.gh-btn.gh-btn-blue');
|
|
|
|
andThen(() => {
|
|
expect(find('#activeTimezone option:selected').text().trim(), 'new timezone after saving')
|
|
.to.equal('(GMT +12:00) International Date Line West');
|
|
});
|
|
|
|
// and now go back to the editor
|
|
visit('/editor/2');
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL in editor')
|
|
.to.equal('/editor/2');
|
|
expect(find('input[name="post-setting-date"]').val(), 'date with blog timezone')
|
|
.to.equal('10 May 16 @ 22:00');
|
|
});
|
|
|
|
// should not do anything if the input date is not different
|
|
fillIn('input[name="post-setting-date"]', '10 May 16 @ 22:00');
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
|
|
andThen(() => {
|
|
expect(find('input[name="post-setting-date"]').val(), 'date didn\'t change')
|
|
.to.equal('10 May 16 @ 22:00');
|
|
});
|
|
|
|
// click on unpublish
|
|
click('.post-save-draft a');
|
|
|
|
andThen(() => {
|
|
expect(find('.post-save-draft').hasClass('active'), 'highlights the active button state for a draft')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'red button to change from published to draft')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for post to unpublish')
|
|
.to.equal('Unpublish');
|
|
});
|
|
|
|
// Unpublish the post
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for draft')
|
|
.to.equal('Save Draft');
|
|
expect(find('.post-save-draft').hasClass('active'), 'highlights the default active button state for a draft')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'no red button expected')
|
|
.to.be.false;
|
|
});
|
|
|
|
// Set the publish date 2 minute to the future to find an error message
|
|
fillIn('input[name="post-setting-date"]', plusTwoMinPacific);
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
|
|
andThen(() => {
|
|
andThen(() => {
|
|
expect(find('.ember-view.response').text().trim(), 'inline error response for invalid date in future')
|
|
.to.equal('Must be at least 2 minutes from now.');
|
|
});
|
|
});
|
|
|
|
// Set the publish date into the future (best to have it 10 minutes from now in the future)
|
|
fillIn('input[name="post-setting-date"]', plusTenMinPacific);
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
|
|
andThen(() => {
|
|
expect(find('label[for="post-setting-date"]').text().trim(), 'label changes to \'Scheduled Date\'')
|
|
.to.equal('Scheduled Date');
|
|
});
|
|
|
|
// click on 'Schedule Post'
|
|
click('.post-save-schedule a');
|
|
|
|
// button should show 'schedule post'
|
|
andThen(() => {
|
|
expect(find('.post-save-schedule').hasClass('active'), 'highlights the active button state for a draft')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'red button to change from published to draft')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for post to schedule')
|
|
.to.equal('Schedule Post');
|
|
});
|
|
|
|
// click on schedule post and save
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
// Dropdown menu should be 'Update Post' and 'Unschedule'
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for scheduled post')
|
|
.to.equal('Update Post');
|
|
expect(find('.post-save-schedule').hasClass('active'), 'highlights the default active button state for a scheduled post')
|
|
.to.be.true;
|
|
expect(find('.post-save-draft').text().trim(), 'not active option should say \'Unschedule\'')
|
|
.to.equal('Unschedule');
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'no red button expected')
|
|
.to.be.false;
|
|
// expect countdown to show warning, that post will be published in x minutes
|
|
expect(find('.gh-notification.gh-notification-schedule').text().trim(), 'notification countdown')
|
|
.to.contain('Post will be published in');
|
|
});
|
|
|
|
// click on 'Unschedule'
|
|
click('.post-save-draft a');
|
|
|
|
andThen(() => {
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button to unscheduled post')
|
|
.to.equal('Unschedule');
|
|
expect(find('.post-save-draft').hasClass('active'), 'highlights the default active button state for a scheduled post')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'red button expected due to status change')
|
|
.to.be.true;
|
|
});
|
|
|
|
// click on unschedule post and save
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for a draft')
|
|
.to.equal('Save Draft');
|
|
expect(find('.post-save-draft').hasClass('active'), 'highlights the default active button state for a draft post')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'red button expected due to status change')
|
|
.to.be.false;
|
|
// expect no countdown notification after unscheduling
|
|
expect(find('.gh-notification.gh-notification-schedule').text().trim(), 'notification countdown')
|
|
.to.equal('');
|
|
});
|
|
});
|
|
|
|
it('handles validation errors when scheduling', function () {
|
|
let saveCount = 0;
|
|
|
|
server.put('/posts/:id/', function ({posts}, {params}) {
|
|
// we have three saves occurring here :-(
|
|
// 1. Auto-save of draft
|
|
// 2. Change of publish time
|
|
// 3. Pressing the Schedule button
|
|
saveCount++;
|
|
if (saveCount === 3) {
|
|
return new Mirage.Response(422, {}, {
|
|
errors: [{
|
|
errorType: 'ValidationError',
|
|
message: 'Error test'
|
|
}]
|
|
});
|
|
} else {
|
|
let attrs = this.normalizedRequestAttrs();
|
|
|
|
return posts.find(params.id).update(attrs);
|
|
}
|
|
});
|
|
|
|
let post = server.create('post', 1);
|
|
let plusTenMin = moment().add(10, 'minutes').format('DD MMM YY @ HH:mm').toString();
|
|
|
|
visit(`/editor/${post.id}`);
|
|
|
|
fillIn('input[name="post-setting-date"]', plusTenMin);
|
|
triggerEvent('input[name="post-setting-date"]', 'blur');
|
|
click('.post-save-schedule a');
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(
|
|
find('.gh-alert').length,
|
|
'number of alerts after failed schedule'
|
|
).to.equal(1);
|
|
|
|
expect(
|
|
find('.gh-alert').text(),
|
|
'alert text after failed schedule'
|
|
).to.match(/Scheduling failed: Error test/);
|
|
});
|
|
});
|
|
|
|
it('handles title validation errors correctly', function () {
|
|
server.createList('post', 1);
|
|
|
|
// post id 1 is a draft, checking for draft behaviour now
|
|
visit('/editor/1');
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL')
|
|
.to.equal('/editor/1');
|
|
});
|
|
|
|
// Test title validation
|
|
fillIn('input[id="entry-title"]', Array(160).join('a'));
|
|
triggerEvent('input[id="entry-title"]', 'blur');
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(
|
|
find('.gh-alert').length,
|
|
'number of alerts after invalid title'
|
|
).to.equal(1);
|
|
|
|
expect(
|
|
find('.gh-alert').text(),
|
|
'alert text after invalid title'
|
|
).to.match(/Title cannot be longer than 150 characters/);
|
|
});
|
|
});
|
|
|
|
it('renders first countdown notification before scheduled time', function () {
|
|
let clock = sinon.useFakeTimers(moment().valueOf());
|
|
let compareDate = moment().tz('Etc/UTC').add(4, 'minutes').format('DD MMM YY @ HH:mm').toString();
|
|
server.create('post', {publishedAt: moment.utc().add(4, 'minutes'), status: 'scheduled'});
|
|
server.create('setting', {activeTimezone: 'Europe/Dublin'});
|
|
clock.restore();
|
|
|
|
visit('/editor/1');
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL')
|
|
.to.equal('/editor/1');
|
|
expect(find('input[name="post-setting-date"]').val(), 'scheduled date')
|
|
.to.equal(compareDate);
|
|
// Dropdown menu should be 'Update Post' and 'Unschedule'
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for scheduled post')
|
|
.to.equal('Update Post');
|
|
expect(find('.post-save-schedule').hasClass('active'), 'highlights the default active button state for a scheduled post')
|
|
.to.be.true;
|
|
expect(find('.post-save-draft').text().trim(), 'not active option should say \'Unschedule\'')
|
|
.to.equal('Unschedule');
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'no red button expected')
|
|
.to.be.false;
|
|
// expect countdown to show warning, that post will be published in x minutes
|
|
expect(find('.gh-notification.gh-notification-schedule').text().trim(), 'notification countdown')
|
|
.to.contain('Post will be published in');
|
|
});
|
|
});
|
|
|
|
it('only shows option to unschedule post 2 minutes before scheduled time', function () {
|
|
let clock = sinon.useFakeTimers(moment().valueOf());
|
|
server.create('post', {publishedAt: moment.utc().add(2, 'minutes'), status: 'scheduled'});
|
|
server.create('setting', {activeTimezone: 'Europe/Dublin'});
|
|
clock.restore();
|
|
|
|
visit('/editor/1');
|
|
|
|
andThen(() => {
|
|
// Save button should say 'Unschedule'
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for scheduled post in status freeze mode')
|
|
.to.equal('Unschedule');
|
|
// expect countdown to show warning, that post will be published in x minutes
|
|
expect(find('.gh-notification.gh-notification-schedule').text().trim(), 'notification countdown')
|
|
.to.contain('Post will be published in');
|
|
// no dropdown menu
|
|
expect(find('.gh-btn.gh-btn-sm.dropdown-toggle').hasClass('active'), 'no dropdown menu')
|
|
.to.be.false;
|
|
});
|
|
});
|
|
|
|
it.skip('lets user unschedule the post shortly before scheduled date', function () {
|
|
let clock = sinon.useFakeTimers(moment().valueOf());
|
|
server.create('post', {publishedAt: moment.utc().add(1, 'minute'), status: 'scheduled'});
|
|
server.create('setting', {activeTimezone: 'Europe/Dublin'});
|
|
clock.restore();
|
|
|
|
visit('/editor/1');
|
|
|
|
// change some text
|
|
fillIn('.markdown-editor', 'Let\'s make some markdown changes');
|
|
|
|
andThen(() => {
|
|
// Save button should say 'Unschedule'
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for scheduled post in status freeze mode')
|
|
.to.equal('Unschedule');
|
|
// expect countdown to show warning, that post will be published in x minutes
|
|
expect(find('.gh-notification.gh-notification-schedule').text().trim(), 'notification countdown')
|
|
.to.contain('Post will be published in');
|
|
// no dropdown menu
|
|
expect(find('.gh-btn.gh-btn-sm.dropdown-toggle').hasClass('active'), 'no dropdown menu')
|
|
.to.be.false;
|
|
});
|
|
|
|
// click on Unschedule
|
|
click('.gh-btn.gh-btn-sm.js-publish-button');
|
|
|
|
andThen(() => {
|
|
expect(find('.markdown-editor').val(), 'changed text in markdown editor')
|
|
.to.equal('Let\'s make some markdown changes');
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').text().trim(), 'text in save button for a draft')
|
|
.to.equal('Save Draft');
|
|
expect(find('.post-save-draft').hasClass('active'), 'highlights the default active button state for a draft post')
|
|
.to.be.true;
|
|
expect(find('.gh-btn.gh-btn-sm.js-publish-button').hasClass('gh-btn-red'), 'red button expected due to status change')
|
|
.to.be.false;
|
|
// expect no countdown notification after unscheduling
|
|
expect(find('.gh-notification.gh-notification-schedule').text().trim(), 'notification countdown')
|
|
.to.equal('');
|
|
});
|
|
});
|
|
|
|
it('shows author list and allows switching of author in PSM', function () {
|
|
server.create('post', {authorId: 1});
|
|
let role = server.create('role', {name: 'Author'});
|
|
let author = server.create('user', {name: 'Waldo', roles: [role]});
|
|
|
|
visit('/editor/1');
|
|
|
|
andThen(() => {
|
|
expect(currentURL(), 'currentURL')
|
|
.to.equal('/editor/1');
|
|
});
|
|
|
|
click('button.post-settings');
|
|
|
|
andThen(() => {
|
|
expect(find('select[name="post-setting-author"]').val()).to.equal('1');
|
|
expect(find('select[name="post-setting-author"] option[value="2"]')).to.be.ok;
|
|
});
|
|
|
|
fillIn('select[name="post-setting-author"]', '2');
|
|
|
|
andThen(() => {
|
|
expect(find('select[name="post-setting-author"]').val()).to.equal('2');
|
|
expect(server.db.posts[0].authorId).to.equal(author.id);
|
|
});
|
|
});
|
|
});
|
|
});
|