mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Move users routes out of settings & change to team
issue #5434 - move users routes/views/controllers out of settings - rename users team - update nav-menu.hbs - remove legacy routes - fix up tests
This commit is contained in:
parent
e7398b0694
commit
f67147a685
19 changed files with 377 additions and 383 deletions
|
@ -30,7 +30,7 @@ export default Ember.Controller.extend({
|
|||
|
||||
user.destroyRecord().then(function () {
|
||||
self.store.unloadAll('post');
|
||||
self.transitionToRoute('settings.users');
|
||||
self.transitionToRoute('team');
|
||||
self.get('notifications').showSuccess('The user has been deleted.', {delayed: true});
|
||||
}, function () {
|
||||
self.get('notifications').showError('The user could not be deleted. Please try again.');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Ember from 'ember';
|
||||
import PaginationControllerMixin from 'ghost/mixins/pagination-controller';
|
||||
|
||||
var UsersIndexController = Ember.ArrayController.extend(PaginationControllerMixin, {
|
||||
var TeamIndexController = Ember.ArrayController.extend(PaginationControllerMixin, {
|
||||
init: function () {
|
||||
// let the PaginationControllerMixin know what type of model we will be paginating
|
||||
// this is necessary because we do not have access to the model inside the Controller::init method
|
||||
|
@ -21,4 +21,4 @@ var UsersIndexController = Ember.ArrayController.extend(PaginationControllerMixi
|
|||
})
|
||||
});
|
||||
|
||||
export default UsersIndexController;
|
||||
export default TeamIndexController;
|
|
@ -5,7 +5,7 @@ var CurrentUserSettings = Ember.Mixin.create({
|
|||
|
||||
return function (user) {
|
||||
if (user.get('isAuthor')) {
|
||||
return self.transitionTo('settings.users.user', user);
|
||||
return self.transitionTo('team.user', user);
|
||||
}
|
||||
|
||||
return user;
|
||||
|
@ -17,7 +17,7 @@ var CurrentUserSettings = Ember.Mixin.create({
|
|||
|
||||
return function (user) {
|
||||
if (user.get('isEditor')) {
|
||||
return self.transitionTo('settings.users');
|
||||
return self.transitionTo('team');
|
||||
}
|
||||
|
||||
return user;
|
||||
|
|
|
@ -40,18 +40,16 @@ Router.map(function () {
|
|||
this.route('edit', {path: ':post_id'});
|
||||
});
|
||||
|
||||
this.route('settings.general', {path: '/settings/general'});
|
||||
this.route('settings.users', {path: '/settings/users'}, function () {
|
||||
this.route('team', {path: '/team'}, function () {
|
||||
this.route('user', {path: ':slug'});
|
||||
});
|
||||
|
||||
this.route('settings.general', {path: '/settings/general'});
|
||||
this.route('settings.tags', {path: '/settings/tags'});
|
||||
this.route('settings.labs', {path: '/settings/labs'});
|
||||
this.route('settings.code-injection', {path: '/settings/code-injection'});
|
||||
this.route('settings.navigation', {path: '/settings/navigation'});
|
||||
|
||||
// Redirect legacy content to posts
|
||||
this.route('content');
|
||||
|
||||
this.route('error404', {path: '/*path'});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
var ContentRoute = Ember.Route.extend({
|
||||
beforeModel: function () {
|
||||
this.transitionTo('posts');
|
||||
}
|
||||
});
|
||||
|
||||
export default ContentRoute;
|
|
@ -1,8 +0,0 @@
|
|||
import Ember from 'ember';
|
||||
var DebugRoute = Ember.Route.extend({
|
||||
beforeModel: function () {
|
||||
this.transitionTo('settings.labs');
|
||||
}
|
||||
});
|
||||
|
||||
export default DebugRoute;
|
|
@ -4,7 +4,7 @@ import PaginationRouteMixin from 'ghost/mixins/pagination-route';
|
|||
import styleBody from 'ghost/mixins/style-body';
|
||||
|
||||
var paginationSettings,
|
||||
UsersIndexRoute;
|
||||
TeamIndexRoute;
|
||||
|
||||
paginationSettings = {
|
||||
page: 1,
|
||||
|
@ -12,10 +12,10 @@ paginationSettings = {
|
|||
status: 'active'
|
||||
};
|
||||
|
||||
UsersIndexRoute = AuthenticatedRoute.extend(styleBody, CurrentUserSettings, PaginationRouteMixin, {
|
||||
TeamIndexRoute = AuthenticatedRoute.extend(styleBody, CurrentUserSettings, PaginationRouteMixin, {
|
||||
titleToken: 'Team',
|
||||
|
||||
classNames: ['settings-view-users'],
|
||||
classNames: ['view-users'],
|
||||
|
||||
setupController: function (controller, model) {
|
||||
this._super(controller, model);
|
||||
|
@ -55,4 +55,4 @@ UsersIndexRoute = AuthenticatedRoute.extend(styleBody, CurrentUserSettings, Pagi
|
|||
}
|
||||
});
|
||||
|
||||
export default UsersIndexRoute;
|
||||
export default TeamIndexRoute;
|
|
@ -2,10 +2,10 @@ import AuthenticatedRoute from 'ghost/routes/authenticated';
|
|||
import CurrentUserSettings from 'ghost/mixins/current-user-settings';
|
||||
import styleBody from 'ghost/mixins/style-body';
|
||||
|
||||
var SettingsUserRoute = AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
||||
var TeamUserRoute = AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
||||
titleToken: 'Team - User',
|
||||
|
||||
classNames: ['settings-view-user'],
|
||||
classNames: ['team-view-user'],
|
||||
|
||||
model: function (params) {
|
||||
var self = this;
|
||||
|
@ -17,7 +17,7 @@ var SettingsUserRoute = AuthenticatedRoute.extend(styleBody, CurrentUserSettings
|
|||
var user = result.findBy('slug', params.slug);
|
||||
|
||||
if (!user) {
|
||||
return self.transitionTo('error404', 'settings/users/' + params.slug);
|
||||
return self.transitionTo('error404', 'team/' + params.slug);
|
||||
}
|
||||
|
||||
return user;
|
||||
|
@ -31,15 +31,15 @@ var SettingsUserRoute = AuthenticatedRoute.extend(styleBody, CurrentUserSettings
|
|||
isAuthor = currentUser.get('isAuthor'),
|
||||
isEditor = currentUser.get('isEditor');
|
||||
if (isAuthor && !isOwnProfile) {
|
||||
self.transitionTo('settings.users.user', currentUser);
|
||||
self.transitionTo('team.user', currentUser);
|
||||
} else if (isEditor && !isOwnProfile && !user.get('isAuthor')) {
|
||||
self.transitionTo('settings.users');
|
||||
self.transitionTo('team');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deactivate: function () {
|
||||
var model = this.modelFor('settings.users.user');
|
||||
var model = this.modelFor('team.user');
|
||||
|
||||
// we want to revert any unsaved changes on exit
|
||||
if (model && model.get('isDirty')) {
|
||||
|
@ -56,4 +56,4 @@ var SettingsUserRoute = AuthenticatedRoute.extend(styleBody, CurrentUserSettings
|
|||
}
|
||||
});
|
||||
|
||||
export default SettingsUserRoute;
|
||||
export default TeamUserRoute;
|
|
@ -10,7 +10,7 @@
|
|||
<ul class="dropdown-menu dropdown-triangle-top js-user-menu-dropdown-menu" role="menu" style="right:-50%;left:auto;margin-right:40px">
|
||||
<li role="presentation">{{#link-to "about" classNames="gh-nav-menu-about dropdown-item js-nav-item" role="menuitem" tabindex="-1"}}<i class="icon-shop"></i> About Ghost{{/link-to}}</li>
|
||||
<li class="divider"></li>
|
||||
<li role="presentation">{{#link-to "settings.users.user" session.user.slug classNames="dropdown-item user-menu-profile js-nav-item" role="menuitem" tabindex="-1"}}<i class="icon-user"></i> Your Profile{{/link-to}}</li>
|
||||
<li role="presentation">{{#link-to "team.user" session.user.slug classNames="dropdown-item user-menu-profile js-nav-item" role="menuitem" tabindex="-1"}}<i class="icon-user"></i> Your Profile{{/link-to}}</li>
|
||||
<li role="presentation">{{#link-to "signout" classNames="dropdown-item user-menu-signout" role="menuitem" tabindex="-1"}}<i class="icon-signout"></i> Sign Out{{/link-to}}</li>
|
||||
</ul>
|
||||
{{/gh-dropdown}}
|
||||
|
@ -24,7 +24,7 @@
|
|||
<li>{{#link-to "editor.new" classNames="gh-nav-main-editor"}}<i class="icon-pen"></i>New Post{{/link-to}}</li>
|
||||
<li>{{#link-to "posts" classNames="gh-nav-main-content"}}<i class="icon-content"></i>Content{{/link-to}}</li>
|
||||
{{!<li><a href="#"><i class="icon-user"></i>My Posts</a></li>}}
|
||||
<li>{{#link-to "settings.users" classNames="gh-nav-main-users"}}<i class="icon-team"></i>Team{{/link-to}}</li>
|
||||
<li>{{#link-to "team" classNames="gh-nav-main-users"}}<i class="icon-team"></i>Team{{/link-to}}</li>
|
||||
{{!<li><a href="#"><i class="icon-idea"></i>Ideas</a></li>}}
|
||||
</ul>
|
||||
{{#if (gh-user-can session.user 'admin')}}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<h4 class="user-list-title">Invited users</h4>
|
||||
|
||||
{{#each invitedUsers itemController="settings/users/user" as |user|}}
|
||||
{{#each invitedUsers itemController="team/user" as |user|}}
|
||||
<div class="user-list-item">
|
||||
<span class="user-list-item-icon icon-mail">ic</span>
|
||||
|
||||
|
@ -37,8 +37,8 @@
|
|||
|
||||
<h4 class="user-list-title">Active users</h4>
|
||||
|
||||
{{#each activeUsers itemController="settings/users/user" as |user|}}
|
||||
{{#link-to 'settings.users.user' user.model class="user-list-item" }}
|
||||
{{#each activeUsers itemController="team/user" as |user|}}
|
||||
{{#link-to 'team.user' user.model class="user-list-item" }}
|
||||
<span class="user-list-item-figure" style={{user.userImageBackground}}>
|
||||
<span class="hidden">Photo of {{user.model.name}}</span>
|
||||
</span>
|
|
@ -1,6 +1,6 @@
|
|||
<header class="view-header">
|
||||
{{#gh-view-title openMobileMenu="openMobileMenu"}}
|
||||
{{#link-to "settings.users"}}Team{{/link-to}} <i class="icon-arrow-right"></i> {{user.name}}
|
||||
{{#link-to "team"}}Team{{/link-to}} <i class="icon-arrow-right"></i> {{user.name}}
|
||||
{{/gh-view-title}}
|
||||
<section class="view-actions">
|
||||
{{#if view.userActionsAreVisible}}
|
|
@ -1,5 +0,0 @@
|
|||
import BaseView from 'ghost/views/settings/content-base';
|
||||
|
||||
var SettingsUserIndexView = BaseView.extend();
|
||||
|
||||
export default SettingsUserIndexView;
|
7
core/client/app/views/team/index.js
Normal file
7
core/client/app/views/team/index.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Ember from 'ember';
|
||||
var TeamUserIndexView = Ember.View.extend({
|
||||
tagName: 'section',
|
||||
classNames: ['gh-view']
|
||||
});
|
||||
|
||||
export default TeamUserIndexView;
|
|
@ -1,7 +1,8 @@
|
|||
import Ember from 'ember';
|
||||
import BaseView from 'ghost/views/settings/content-base';
|
||||
|
||||
var SettingsUserView = BaseView.extend({
|
||||
var TeamUserView = Ember.View.extend({
|
||||
tagName: 'section',
|
||||
classNames: ['gh-view'],
|
||||
currentUser: Ember.computed.alias('controller.session.user'),
|
||||
|
||||
isNotOwnProfile: Ember.computed('controller.user.id', 'currentUser.id', function () {
|
||||
|
@ -28,4 +29,4 @@ var SettingsUserView = BaseView.extend({
|
|||
|
||||
});
|
||||
|
||||
export default SettingsUserView;
|
||||
export default TeamUserView;
|
|
@ -66,7 +66,7 @@ screens = {
|
|||
selector: '.gh-nav-main-content.active'
|
||||
},
|
||||
content: {
|
||||
url: 'ghost/content/',
|
||||
url: 'ghost/',
|
||||
linkSelector: '.gh-nav-main-content',
|
||||
selector: '.gh-nav-main-content.active'
|
||||
},
|
||||
|
@ -89,13 +89,13 @@ screens = {
|
|||
url: 'ghost/settings/general',
|
||||
selector: '.gh-nav-settings-general.active'
|
||||
},
|
||||
'settings.users': {
|
||||
url: 'ghost/settings/users',
|
||||
team: {
|
||||
url: 'ghost/team',
|
||||
linkSelector: '.gh-nav-main-users',
|
||||
selector: '.gh-nav-main-users.active'
|
||||
},
|
||||
'settings.users.user': {
|
||||
url: 'ghost/settings/users/test',
|
||||
'team.user': {
|
||||
url: 'ghost/team/test',
|
||||
linkSelector: '.user-menu-profile',
|
||||
selector: '.user-profile'
|
||||
},
|
||||
|
|
|
@ -39,7 +39,7 @@ CasperTest.begin('Admin navigation bar is correct', 65, function suite(test) {
|
|||
// Users
|
||||
test.assertExists('.gh-nav-main-users', 'Users nav item exists');
|
||||
test.assertSelectorHasText('.gh-nav-main-users', 'Team', 'Users nav item has correct text');
|
||||
test.assertEquals(usersHref, '/ghost/settings/users/', 'Users href is correct');
|
||||
test.assertEquals(usersHref, '/ghost/team/', 'Users href is correct');
|
||||
test.assertDoesntExist('.gh-nav-main-users.active', 'Users nav item is not marked active');
|
||||
|
||||
// Settings - General
|
||||
|
@ -139,7 +139,7 @@ CasperTest.begin('Admin navigation bar is correct', 65, function suite(test) {
|
|||
test.assertExists('.dropdown-item.user-menu-profile', 'Profile menu item exists');
|
||||
test.assertSelectorHasText('.dropdown-item.user-menu-profile', 'Your Profile',
|
||||
'Profile menu item has correct text');
|
||||
test.assertEquals(profileHref, '/ghost/settings/users/' + newUser.slug + '/', 'Profile href is correct');
|
||||
test.assertEquals(profileHref, '/ghost/team/' + newUser.slug + '/', 'Profile href is correct');
|
||||
|
||||
test.assertExists('.user-menu-signout', 'Sign Out menu item exists');
|
||||
test.assertSelectorHasText('.user-menu-signout', 'Sign Out', 'Signout menu item has correct text');
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
|
||||
// These classes relate to elements which only appear when a given tab is loaded.
|
||||
// These are used to check that a switch to a tab is complete, or that we are on the right tab.
|
||||
var generalTabDetector = '.gh-nav-settings-general.active',
|
||||
usersTabDetector = '.gh-nav-main-users';
|
||||
var generalTabDetector = '.gh-nav-settings-general.active';
|
||||
|
||||
CasperTest.begin('Settings screen is correct', 9, function suite(test) {
|
||||
CasperTest.begin('Settings screen is correct', 5, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.general', function testTitleAndUrl() {
|
||||
test.assertTitle('Settings - General - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/settings\/general\/$/, 'Landed on the correct URL');
|
||||
|
@ -19,24 +18,6 @@ CasperTest.begin('Settings screen is correct', 9, function suite(test) {
|
|||
test.assertExists(generalTabDetector, 'Form is present');
|
||||
test.assertSelectorHasText('.view-title', 'General', 'Title is "General"');
|
||||
});
|
||||
|
||||
// TODO move users tests to a new file and make sure settings nav tests are refactored into app_test.js
|
||||
|
||||
casper.then(function testSwitchingTabs() {
|
||||
casper.thenClick('.gh-nav-main-users');
|
||||
casper.waitForSelector(usersTabDetector, function then() {
|
||||
// assert that the right menu item is active
|
||||
test.assertExists('.gh-nav-main-users.active', 'Users link is active');
|
||||
test.assertDoesntExist('.gh-nav-settings-general.active', 'General link is not active');
|
||||
}, casper.failOnTimeout(test, 'waitForSelector `usersTabDetector` timed out'));
|
||||
|
||||
casper.thenClick('.gh-nav-settings-general');
|
||||
casper.waitForSelector(generalTabDetector, function then() {
|
||||
// assert that the right menu item is active
|
||||
test.assertExists('.gh-nav-settings-general.active', 'General link is active');
|
||||
test.assertDoesntExist('.gh-nav-main-users.active', 'User link is not active');
|
||||
}, casper.failOnTimeout(test, 'waitForSelector `generalTabDetector` timed out'));
|
||||
});
|
||||
});
|
||||
|
||||
// ## General settings tests
|
||||
|
@ -153,307 +134,3 @@ CasperTest.begin('General settings validation is correct', 6, function suite(tes
|
|||
test.assertField('general[postsPerPage]', '5', 'posts per page is set correctly');
|
||||
});
|
||||
});
|
||||
//
|
||||
CasperTest.begin('Users screen is correct', 9, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.general');
|
||||
casper.thenTransitionAndWaitForScreenLoad('settings.users', function canTransition() {
|
||||
test.assert(true, 'Can transition to users screen from settings.general');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/$/, 'settings.users transitions to correct url');
|
||||
});
|
||||
casper.then(function usersScreenHasContent() {
|
||||
test.assertSelectorHasText('.settings-users .user-list .user-list-title', 'Active users', 'active users text is correct');
|
||||
test.assertExists('.settings-users .user-list .user-list-item', 'Has an active user');
|
||||
test.assertSelectorHasText('.settings-users .user-list-item .name', 'Test User', 'test user text is correct');
|
||||
test.assertExists('.settings-users .user-list-item .role-label.owner', 'First user has owner role displayed');
|
||||
|
||||
test.assertExists('.view-actions .btn-green', 'Add user button is on page.');
|
||||
});
|
||||
casper.thenClick('.view-actions .btn-green');
|
||||
casper.waitForOpaque('.invite-new-user .modal-content', function then() {
|
||||
test.assertEval(function testOwnerRoleNotAnOption() {
|
||||
var options = document.querySelectorAll('.invite-new-user select#new-user-role option'),
|
||||
i = 0;
|
||||
for (; i < options.length; i = i + 1) {
|
||||
if (options[i].text === 'Owner') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, '"Owner" is not a role option for new users');
|
||||
});
|
||||
// role options get loaded asynchronously; give them a chance to come in
|
||||
casper.waitForSelector('.invite-new-user select#new-user-role option', function then() {
|
||||
test.assertEval(function authorIsSelectedByDefault() {
|
||||
var options = document.querySelectorAll('.invite-new-user select#new-user-role option'),
|
||||
i = 0;
|
||||
for (; i < options.length; i = i + 1) {
|
||||
if (options[i].selected) {
|
||||
return options[i].text === 'Author';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, 'The "Author" role is selected by default when adding a new user');
|
||||
});
|
||||
});
|
||||
// ### User settings tests
|
||||
CasperTest.begin('Can save settings', 7, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.users.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost Admin title is correct');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/test\/$/, 'settings.users.user has correct URL');
|
||||
});
|
||||
|
||||
function handleUserRequest(requestData) {
|
||||
// make sure we only get requests from the user pane
|
||||
if (requestData.url.indexOf('settings/') !== -1) {
|
||||
test.fail('Saving the user pane triggered another settings pane to save');
|
||||
}
|
||||
}
|
||||
|
||||
function handleSettingsRequest(requestData) {
|
||||
// make sure we only get requests from the user pane
|
||||
if (requestData.url.indexOf('users/') !== -1) {
|
||||
test.fail('Saving a settings pane triggered the user pane to save');
|
||||
}
|
||||
}
|
||||
|
||||
casper.then(function listenForRequests() {
|
||||
casper.on('resource.requested', handleUserRequest);
|
||||
});
|
||||
|
||||
casper.thenClick('.btn-blue');
|
||||
casper.waitFor(function successNotification() {
|
||||
return this.evaluate(function () {
|
||||
return document.querySelectorAll('.gh-notification').length > 0;
|
||||
});
|
||||
}, function doneWaiting() {
|
||||
test.pass('Waited for notification');
|
||||
}, casper.failOnTimeout(test, 'Saving the user pane did not result in a notification'));
|
||||
|
||||
casper.then(function checkUserWasSaved() {
|
||||
casper.removeListener('resource.requested', handleUserRequest);
|
||||
});
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, casper.failOnTimeout(test, 'No success notification :('));
|
||||
|
||||
casper.thenClick('.gh-nav-settings-general').then(function testTransitionToGeneral() {
|
||||
casper.waitForSelector(generalTabDetector, function then() {
|
||||
casper.on('resource.requested', handleSettingsRequest);
|
||||
test.assertEval(function testGeneralIsActive() {
|
||||
return document.querySelector('.gh-nav-settings-general').classList.contains('active');
|
||||
}, 'general tab is marked active');
|
||||
},
|
||||
casper.failOnTimeout(test, 'waitForSelector `usersTabDetector` timed out'));
|
||||
});
|
||||
|
||||
casper.thenClick('.btn-blue').waitFor(function successNotification() {
|
||||
return this.evaluate(function () {
|
||||
return document.querySelectorAll('.gh-notification').length > 0;
|
||||
});
|
||||
}, function doneWaiting() {
|
||||
test.pass('Waited for notification');
|
||||
}, casper.failOnTimeout(test, 'Saving the general pane did not result in a notification'));
|
||||
|
||||
casper.then(function checkSettingsWereSaved() {
|
||||
casper.removeListener('resource.requested', handleSettingsRequest);
|
||||
});
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, casper.failOnTimeout(test, 'No success notification :('));
|
||||
|
||||
CasperTest.beforeDone(function () {
|
||||
casper.removeListener('resource.requested', handleUserRequest);
|
||||
casper.removeListener('resource.requested', handleSettingsRequest);
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('User settings screen resets all whitespace slug to original value', 3, function suite(test) {
|
||||
var slug;
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('settings.users.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function getSlugValue() {
|
||||
slug = this.evaluate(function () {
|
||||
return document.querySelector('#user-slug').value;
|
||||
});
|
||||
});
|
||||
|
||||
casper.then(function changeSlugInput() {
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-slug': ' '
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('body');
|
||||
|
||||
casper.then(function checkSlugInputValue() {
|
||||
casper.wait(250);
|
||||
test.assertField('user', slug, 'user slug is correct');
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('User settings screen change slug handles duplicate slug', 4, function suite(test) {
|
||||
var slug;
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('settings.users.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function getSlugValue() {
|
||||
slug = this.evaluate(function () {
|
||||
return document.querySelector('#user-slug').value;
|
||||
});
|
||||
});
|
||||
|
||||
casper.then(function changeSlug() {
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-slug': slug + '!'
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('body');
|
||||
|
||||
casper.waitForResource(/\/slugs\/user\//, function testGoodResponse(resource) {
|
||||
test.assert(resource.status < 400, 'resource.status < 400');
|
||||
});
|
||||
|
||||
casper.then(function checkSlugInputValue() {
|
||||
test.assertField('user', slug, 'user slug is correct');
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('User settings screen validates email', 6, function suite(test) {
|
||||
var email;
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('settings.users.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function getEmail() {
|
||||
email = this.evaluate(function () {
|
||||
return document.querySelector('#user-email').value;
|
||||
});
|
||||
});
|
||||
|
||||
casper.then(function setEmailToInvalid() {
|
||||
var brokenEmail = email.replace('.', '-');
|
||||
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-email': brokenEmail
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('.btn-blue');
|
||||
|
||||
casper.waitForResource('/users/');
|
||||
|
||||
casper.waitForSelector('.notification-error', function onSuccess() {
|
||||
test.assert(true, 'Got error notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]', 'notification text is not broken');
|
||||
}, casper.failOnTimeout(test, 'No error notification :('));
|
||||
|
||||
casper.then(function resetEmailToValid() {
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-email': email
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('.view-actions .btn-blue');
|
||||
|
||||
casper.waitForResource(/users/);
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-success', '[object Object]', 'notification text is not broken');
|
||||
}, casper.failOnTimeout(test, 'No success notification :('));
|
||||
});
|
||||
|
||||
// TODO: user needs to be loaded whenever it is edited (multi user)
|
||||
CasperTest.begin('User settings screen shows remaining characters for Bio properly', 4, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.users.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
function getRemainingBioCharacterCount() {
|
||||
return casper.getHTML('.word-count');
|
||||
}
|
||||
|
||||
casper.then(function checkCharacterCount() {
|
||||
test.assert(getRemainingBioCharacterCount() === '200', 'Bio remaining characters is 200');
|
||||
});
|
||||
|
||||
casper.then(function setBioToValid() {
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-bio': 'asdf\n' // 5 characters
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.then(function checkCharacterCount() {
|
||||
test.assert(getRemainingBioCharacterCount() === '195', 'Bio remaining characters is 195');
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('Ensure user bio field length validation', 3, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.users.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function setBioToInvalid() {
|
||||
this.fillSelectors('form.user-profile', {
|
||||
'#user-bio': new Array(202).join('a')
|
||||
});
|
||||
});
|
||||
|
||||
casper.thenClick('.view-actions .btn-blue');
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
test.assertSelectorHasText('.notification-error', 'is too long', '.notification-error text is correct');
|
||||
}, casper.failOnTimeout(test, 'Bio field length error did not appear', 2000));
|
||||
});
|
||||
|
||||
CasperTest.begin('Ensure user url field validation', 3, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.users.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function setWebsiteToInvalid() {
|
||||
this.fillSelectors('form.user-profile', {
|
||||
'#user-website': 'notaurl'
|
||||
});
|
||||
});
|
||||
|
||||
casper.thenClick('.view-actions .btn-blue');
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
test.assertSelectorHasText('.notification-error', 'not a valid url', '.notification-error text is correct');
|
||||
}, casper.failOnTimeout(test, 'Url validation error did not appear', 2000));
|
||||
});
|
||||
|
||||
CasperTest.begin('Ensure user location field length validation', 3, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.users.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/settings\/users\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function setLocationToInvalid() {
|
||||
this.fillSelectors('form.user-profile', {
|
||||
'#user-location': new Array(1002).join('a')
|
||||
});
|
||||
});
|
||||
|
||||
casper.thenClick('.view-actions .btn-blue');
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
test.assertSelectorHasText('.notification-error', 'is too long', '.notification-error text is correct');
|
||||
}, casper.failOnTimeout(test, 'Location field length error did not appear', 2000));
|
||||
});
|
||||
|
|
332
core/test/functional/client/team_test.js
Normal file
332
core/test/functional/client/team_test.js
Normal file
|
@ -0,0 +1,332 @@
|
|||
// # Settings Test
|
||||
|
||||
/*globals CasperTest, casper */
|
||||
|
||||
// These classes relate to elements which only appear when a given tab is loaded.
|
||||
// These are used to check that a switch to a tab is complete, or that we are on the right tab.
|
||||
var generalTabDetector = '.gh-nav-settings-general.active',
|
||||
usersTabDetector = '.gh-nav-main-users';
|
||||
|
||||
CasperTest.begin('Team tab is correct', 4, function suite(test) {
|
||||
// TODO make sure settings nav tests are refactored into app_test.js
|
||||
|
||||
casper.then(function testSwitchingTabs() {
|
||||
casper.thenClick('.gh-nav-main-users');
|
||||
casper.waitForSelector(usersTabDetector, function then() {
|
||||
// assert that the right menu item is active
|
||||
test.assertExists('.gh-nav-main-users.active', 'Users link is active');
|
||||
test.assertDoesntExist('.gh-nav-settings-general.active', 'General link is not active');
|
||||
}, casper.failOnTimeout(test, 'waitForSelector `usersTabDetector` timed out'));
|
||||
|
||||
casper.thenClick('.gh-nav-settings-general');
|
||||
casper.waitForSelector(generalTabDetector, function then() {
|
||||
// assert that the right menu item is active
|
||||
test.assertExists('.gh-nav-settings-general.active', 'General link is active');
|
||||
test.assertDoesntExist('.gh-nav-main-users.active', 'User link is not active');
|
||||
}, casper.failOnTimeout(test, 'waitForSelector `generalTabDetector` timed out'));
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('Users screen is correct', 9, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('settings.general');
|
||||
casper.thenTransitionAndWaitForScreenLoad('team', function canTransition() {
|
||||
test.assert(true, 'Can transition to users screen from settings.general');
|
||||
test.assertUrlMatch(/ghost\/team\/$/, 'team transitions to correct url');
|
||||
});
|
||||
casper.then(function usersScreenHasContent() {
|
||||
test.assertSelectorHasText('.settings-users .user-list .user-list-title', 'Active users', 'active users text is correct');
|
||||
test.assertExists('.settings-users .user-list .user-list-item', 'Has an active user');
|
||||
test.assertSelectorHasText('.settings-users .user-list-item .name', 'Test User', 'test user text is correct');
|
||||
test.assertExists('.settings-users .user-list-item .role-label.owner', 'First user has owner role displayed');
|
||||
|
||||
test.assertExists('.view-actions .btn-green', 'Add user button is on page.');
|
||||
});
|
||||
casper.thenClick('.view-actions .btn-green');
|
||||
casper.waitForOpaque('.invite-new-user .modal-content', function then() {
|
||||
test.assertEval(function testOwnerRoleNotAnOption() {
|
||||
var options = document.querySelectorAll('.invite-new-user select#new-user-role option'),
|
||||
i = 0;
|
||||
for (; i < options.length; i = i + 1) {
|
||||
if (options[i].text === 'Owner') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, '"Owner" is not a role option for new users');
|
||||
});
|
||||
// role options get loaded asynchronously; give them a chance to come in
|
||||
casper.waitForSelector('.invite-new-user select#new-user-role option', function then() {
|
||||
test.assertEval(function authorIsSelectedByDefault() {
|
||||
var options = document.querySelectorAll('.invite-new-user select#new-user-role option'),
|
||||
i = 0;
|
||||
for (; i < options.length; i = i + 1) {
|
||||
if (options[i].selected) {
|
||||
return options[i].text === 'Author';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, 'The "Author" role is selected by default when adding a new user');
|
||||
});
|
||||
});
|
||||
// ### User settings tests
|
||||
CasperTest.begin('Can save settings', 7, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('team.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost Admin title is correct');
|
||||
test.assertUrlMatch(/ghost\/team\/test\/$/, 'team.user has correct URL');
|
||||
});
|
||||
|
||||
function handleUserRequest(requestData) {
|
||||
// make sure we only get requests from the user pane
|
||||
if (requestData.url.indexOf('settings/') !== -1) {
|
||||
test.fail('Saving the user pane triggered another settings pane to save');
|
||||
}
|
||||
}
|
||||
|
||||
function handleSettingsRequest(requestData) {
|
||||
// make sure we only get requests from the user pane
|
||||
if (requestData.url.indexOf('team/') !== -1) {
|
||||
test.fail('Saving a settings pane triggered the user pane to save');
|
||||
}
|
||||
}
|
||||
|
||||
casper.then(function listenForRequests() {
|
||||
casper.on('resource.requested', handleUserRequest);
|
||||
});
|
||||
|
||||
casper.thenClick('.btn-blue');
|
||||
casper.waitFor(function successNotification() {
|
||||
return this.evaluate(function () {
|
||||
return document.querySelectorAll('.gh-notification').length > 0;
|
||||
});
|
||||
}, function doneWaiting() {
|
||||
test.pass('Waited for notification');
|
||||
}, casper.failOnTimeout(test, 'Saving the user pane did not result in a notification'));
|
||||
|
||||
casper.then(function checkUserWasSaved() {
|
||||
casper.removeListener('resource.requested', handleUserRequest);
|
||||
});
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, casper.failOnTimeout(test, 'No success notification :('));
|
||||
|
||||
casper.thenClick('.gh-nav-settings-general').then(function testTransitionToGeneral() {
|
||||
casper.waitForSelector(generalTabDetector, function then() {
|
||||
casper.on('resource.requested', handleSettingsRequest);
|
||||
test.assertEval(function testGeneralIsActive() {
|
||||
return document.querySelector('.gh-nav-settings-general').classList.contains('active');
|
||||
}, 'general tab is marked active');
|
||||
},
|
||||
casper.failOnTimeout(test, 'waitForSelector `usersTabDetector` timed out'));
|
||||
});
|
||||
|
||||
casper.thenClick('.btn-blue').waitFor(function successNotification() {
|
||||
return this.evaluate(function () {
|
||||
return document.querySelectorAll('.gh-notification').length > 0;
|
||||
});
|
||||
}, function doneWaiting() {
|
||||
test.pass('Waited for notification');
|
||||
}, casper.failOnTimeout(test, 'Saving the general pane did not result in a notification'));
|
||||
|
||||
casper.then(function checkSettingsWereSaved() {
|
||||
casper.removeListener('resource.requested', handleSettingsRequest);
|
||||
});
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
}, casper.failOnTimeout(test, 'No success notification :('));
|
||||
|
||||
CasperTest.beforeDone(function () {
|
||||
casper.removeListener('resource.requested', handleUserRequest);
|
||||
casper.removeListener('resource.requested', handleSettingsRequest);
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('User settings screen resets all whitespace slug to original value', 3, function suite(test) {
|
||||
var slug;
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('team.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/team\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function getSlugValue() {
|
||||
slug = this.evaluate(function () {
|
||||
return document.querySelector('#user-slug').value;
|
||||
});
|
||||
});
|
||||
|
||||
casper.then(function changeSlugInput() {
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-slug': ' '
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('body');
|
||||
|
||||
casper.then(function checkSlugInputValue() {
|
||||
casper.wait(250);
|
||||
test.assertField('user', slug, 'user slug is correct');
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('User settings screen change slug handles duplicate slug', 4, function suite(test) {
|
||||
var slug;
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('team.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/team\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function getSlugValue() {
|
||||
slug = this.evaluate(function () {
|
||||
return document.querySelector('#user-slug').value;
|
||||
});
|
||||
});
|
||||
|
||||
casper.then(function changeSlug() {
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-slug': slug + '!'
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('body');
|
||||
|
||||
casper.waitForResource(/\/slugs\/user\//, function testGoodResponse(resource) {
|
||||
test.assert(resource.status < 400, 'resource.status < 400');
|
||||
});
|
||||
|
||||
casper.then(function checkSlugInputValue() {
|
||||
test.assertField('user', slug, 'user slug is correct');
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('User settings screen validates email', 6, function suite(test) {
|
||||
var email;
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('team.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/team\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function getEmail() {
|
||||
email = this.evaluate(function () {
|
||||
return document.querySelector('#user-email').value;
|
||||
});
|
||||
});
|
||||
|
||||
casper.then(function setEmailToInvalid() {
|
||||
var brokenEmail = email.replace('.', '-');
|
||||
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-email': brokenEmail
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('.btn-blue');
|
||||
|
||||
casper.waitForResource('/team/');
|
||||
|
||||
casper.waitForSelector('.notification-error', function onSuccess() {
|
||||
test.assert(true, 'Got error notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]', 'notification text is not broken');
|
||||
}, casper.failOnTimeout(test, 'No error notification :('));
|
||||
|
||||
casper.then(function resetEmailToValid() {
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-email': email
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.thenClick('.view-actions .btn-blue');
|
||||
|
||||
casper.waitForResource(/users/);
|
||||
|
||||
casper.waitForSelector('.notification-success', function onSuccess() {
|
||||
test.assert(true, 'Got success notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-success', '[object Object]', 'notification text is not broken');
|
||||
}, casper.failOnTimeout(test, 'No success notification :('));
|
||||
});
|
||||
|
||||
// TODO: user needs to be loaded whenever it is edited (multi user)
|
||||
CasperTest.begin('User settings screen shows remaining characters for Bio properly', 4, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('team.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/team\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
function getRemainingBioCharacterCount() {
|
||||
return casper.getHTML('.word-count');
|
||||
}
|
||||
|
||||
casper.then(function checkCharacterCount() {
|
||||
test.assert(getRemainingBioCharacterCount() === '200', 'Bio remaining characters is 200');
|
||||
});
|
||||
|
||||
casper.then(function setBioToValid() {
|
||||
casper.fillSelectors('.user-profile', {
|
||||
'#user-bio': 'asdf\n' // 5 characters
|
||||
}, false);
|
||||
});
|
||||
|
||||
casper.then(function checkCharacterCount() {
|
||||
test.assert(getRemainingBioCharacterCount() === '195', 'Bio remaining characters is 195');
|
||||
});
|
||||
});
|
||||
|
||||
CasperTest.begin('Ensure user bio field length validation', 3, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('team.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/team\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function setBioToInvalid() {
|
||||
this.fillSelectors('form.user-profile', {
|
||||
'#user-bio': new Array(202).join('a')
|
||||
});
|
||||
});
|
||||
|
||||
casper.thenClick('.view-actions .btn-blue');
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
test.assertSelectorHasText('.notification-error', 'is too long', '.notification-error text is correct');
|
||||
}, casper.failOnTimeout(test, 'Bio field length error did not appear', 2000));
|
||||
});
|
||||
|
||||
CasperTest.begin('Ensure user url field validation', 3, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('team.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/team\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function setWebsiteToInvalid() {
|
||||
this.fillSelectors('form.user-profile', {
|
||||
'#user-website': 'notaurl'
|
||||
});
|
||||
});
|
||||
|
||||
casper.thenClick('.view-actions .btn-blue');
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
test.assertSelectorHasText('.notification-error', 'not a valid url', '.notification-error text is correct');
|
||||
}, casper.failOnTimeout(test, 'Url validation error did not appear', 2000));
|
||||
});
|
||||
|
||||
CasperTest.begin('Ensure user location field length validation', 3, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('team.user', function testTitleAndUrl() {
|
||||
test.assertTitle('Team - User - Test Blog', 'Ghost admin has incorrect title');
|
||||
test.assertUrlMatch(/ghost\/team\/test\/$/, 'Ghost doesn\'t require login this time');
|
||||
});
|
||||
|
||||
casper.then(function setLocationToInvalid() {
|
||||
this.fillSelectors('form.user-profile', {
|
||||
'#user-location': new Array(1002).join('a')
|
||||
});
|
||||
});
|
||||
|
||||
casper.thenClick('.view-actions .btn-blue');
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
test.assertSelectorHasText('.notification-error', 'is too long', '.notification-error text is correct');
|
||||
}, casper.failOnTimeout(test, 'Location field length error did not appear', 2000));
|
||||
});
|
Loading…
Add table
Reference in a new issue