mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 03:44:29 +03:00
Add acceptance test for setup flow happy-path
refs #6039 - add `jquery-deparam` ember testing dependency for use in mirage config - setup necessary mirage fixtures & endpoints for successful testing of setup flow's happy-path - add happy-path acceptance test for setup flow
This commit is contained in:
parent
074346f6ce
commit
675a1221fa
@ -1,12 +1,14 @@
|
|||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
|
|
||||||
const {isBlank} = Ember;
|
let {isBlank} = Ember;
|
||||||
|
|
||||||
function paginatedResponse(modelName, allModels, request) {
|
function paginatedResponse(modelName, allModels, request) {
|
||||||
const page = +request.queryParams.page || 1;
|
let page = +request.queryParams.page || 1;
|
||||||
let limit = request.queryParams.limit || 15;
|
let limit = request.queryParams.limit || 15;
|
||||||
let pages, models, next, prev;
|
let pages, models, next, prev;
|
||||||
|
|
||||||
|
allModels = allModels || [];
|
||||||
|
|
||||||
if (limit === 'all') {
|
if (limit === 'all') {
|
||||||
models = allModels;
|
models = allModels;
|
||||||
pages = 1;
|
pages = 1;
|
||||||
@ -48,6 +50,27 @@ export default function () {
|
|||||||
this.namespace = 'ghost/api/v0.1'; // make this `api`, for example, if your API is namespaced
|
this.namespace = 'ghost/api/v0.1'; // make this `api`, for example, if your API is namespaced
|
||||||
// this.timing = 400; // delay for each request, automatically set to 0 during testing
|
// this.timing = 400; // delay for each request, automatically set to 0 during testing
|
||||||
|
|
||||||
|
/* Authentication ------------------------------------------------------- */
|
||||||
|
|
||||||
|
this.post('/authentication/token', function () {
|
||||||
|
return {
|
||||||
|
access_token: '5JhTdKI7PpoZv4ROsFoERc6wCHALKFH5jxozwOOAErmUzWrFNARuH1q01TYTKeZkPW7FmV5MJ2fU00pg9sm4jtH3Z1LjCf8D6nNqLYCfFb2YEKyuvG7zHj4jZqSYVodN2YTCkcHv6k8oJ54QXzNTLIDMlCevkOebm5OjxGiJpafMxncm043q9u1QhdU9eee3zouGRMVVp8zkKVoo5zlGMi3zvS2XDpx7xsfk8hKHpUgd7EDDQxmMueifWv7hv6n',
|
||||||
|
expires_in: 3600,
|
||||||
|
refresh_token: 'XP13eDjwV5mxOcrq1jkIY9idhdvN3R1Br5vxYpYIub2P5Hdc8pdWMOGmwFyoUshiEB62JWHTl8H1kACJR18Z8aMXbnk5orG28br2kmVgtVZKqOSoiiWrQoeKTqrRV0t7ua8uY5HdDUaKpnYKyOdpagsSPn3WEj8op4vHctGL3svOWOjZhq6F2XeVPMR7YsbiwBE8fjT3VhTB3KRlBtWZd1rE0Qo2EtSplWyjGKv1liAEiL0ndQoLeeSOCH4rTP7',
|
||||||
|
token_type: 'Bearer'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Download Count ------------------------------------------------------- */
|
||||||
|
|
||||||
|
let downloadCount = 0;
|
||||||
|
this.get('http://ghost.org/count/', function () {
|
||||||
|
downloadCount++;
|
||||||
|
return {
|
||||||
|
count: downloadCount
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
/* Notifications -------------------------------------------------------- */
|
/* Notifications -------------------------------------------------------- */
|
||||||
|
|
||||||
this.get('/notifications/', 'notifications');
|
this.get('/notifications/', 'notifications');
|
||||||
@ -55,13 +78,14 @@ export default function () {
|
|||||||
/* Posts ---------------------------------------------------------------- */
|
/* Posts ---------------------------------------------------------------- */
|
||||||
|
|
||||||
this.post('/posts/', function (db, request) {
|
this.post('/posts/', function (db, request) {
|
||||||
const [attrs] = JSON.parse(request.requestBody).posts;
|
let [attrs] = JSON.parse(request.requestBody).posts;
|
||||||
let post;
|
let post;
|
||||||
|
|
||||||
if (isBlank(attrs.slug) && !isBlank(attrs.title)) {
|
if (isBlank(attrs.slug) && !isBlank(attrs.title)) {
|
||||||
attrs.slug = attrs.title.dasherize();
|
attrs.slug = attrs.title.dasherize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: this does not use the post factory to fill in blank fields
|
||||||
post = db.posts.insert(attrs);
|
post = db.posts.insert(attrs);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -69,11 +93,21 @@ export default function () {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.get('/posts/', function (db, request) {
|
||||||
|
// TODO: handle status/staticPages/author params
|
||||||
|
let response = paginatedResponse('posts', db.posts, request);
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Roles ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
this.get('/roles/', 'roles');
|
||||||
|
|
||||||
/* Settings ------------------------------------------------------------- */
|
/* Settings ------------------------------------------------------------- */
|
||||||
|
|
||||||
this.get('/settings/', function (db, request) {
|
this.get('/settings/', function (db, request) {
|
||||||
const filters = request.queryParams.type.split(','),
|
let filters = request.queryParams.type.split(',');
|
||||||
settings = [];
|
let settings = [];
|
||||||
|
|
||||||
filters.forEach(filter => {
|
filters.forEach(filter => {
|
||||||
settings.pushObjects(db.settings.where({type: filter}));
|
settings.pushObjects(db.settings.where({type: filter}));
|
||||||
@ -90,7 +124,7 @@ export default function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.put('/settings/', function (db, request) {
|
this.put('/settings/', function (db, request) {
|
||||||
const newSettings = JSON.parse(request.requestBody);
|
let newSettings = JSON.parse(request.requestBody);
|
||||||
|
|
||||||
db.settings.remove();
|
db.settings.remove();
|
||||||
db.settings.insert(newSettings);
|
db.settings.insert(newSettings);
|
||||||
@ -111,16 +145,52 @@ export default function () {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* Setup ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
this.post('/authentication/setup', function (db, request) {
|
||||||
|
let [attrs] = $.deparam(request.requestBody).setup;
|
||||||
|
let [role] = db.roles.where({name: 'Owner'});
|
||||||
|
let user;
|
||||||
|
|
||||||
|
// create owner role unless already exists
|
||||||
|
if (!role) {
|
||||||
|
role = db.roles.insert({name: 'Owner'});
|
||||||
|
}
|
||||||
|
attrs.roles = [role];
|
||||||
|
|
||||||
|
if (!isBlank(attrs.email)) {
|
||||||
|
attrs.slug = attrs.email.split('@')[0].dasherize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: this does not use the user factory to fill in blank fields
|
||||||
|
user = db.users.insert(attrs);
|
||||||
|
|
||||||
|
delete user.roles;
|
||||||
|
|
||||||
|
return {
|
||||||
|
users: [user]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.get('/authentication/setup/', function () {
|
||||||
|
return {
|
||||||
|
setup: [
|
||||||
|
{status: true}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
/* Tags ----------------------------------------------------------------- */
|
/* Tags ----------------------------------------------------------------- */
|
||||||
|
|
||||||
this.post('/tags/', function (db, request) {
|
this.post('/tags/', function (db, request) {
|
||||||
const [attrs] = JSON.parse(request.requestBody).tags;
|
let [attrs] = JSON.parse(request.requestBody).tags;
|
||||||
let tag;
|
let tag;
|
||||||
|
|
||||||
if (isBlank(attrs.slug) && !isBlank(attrs.name)) {
|
if (isBlank(attrs.slug) && !isBlank(attrs.name)) {
|
||||||
attrs.slug = attrs.name.dasherize();
|
attrs.slug = attrs.name.dasherize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: this does not use the tag factory to fill in blank fields
|
||||||
tag = db.tags.insert(attrs);
|
tag = db.tags.insert(attrs);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -129,13 +199,13 @@ export default function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.get('/tags/', function (db, request) {
|
this.get('/tags/', function (db, request) {
|
||||||
const response = paginatedResponse('tags', db.tags, request);
|
let response = paginatedResponse('tags', db.tags, request);
|
||||||
// TODO: remove post_count unless requested?
|
// TODO: remove post_count unless requested?
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.get('/tags/slug/:slug/', function (db, request) {
|
this.get('/tags/slug/:slug/', function (db, request) {
|
||||||
const [tag] = db.tags.where({slug: request.params.slug});
|
let [tag] = db.tags.where({slug: request.params.slug});
|
||||||
|
|
||||||
// TODO: remove post_count unless requested?
|
// TODO: remove post_count unless requested?
|
||||||
|
|
||||||
@ -145,9 +215,9 @@ export default function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.put('/tags/:id/', function (db, request) {
|
this.put('/tags/:id/', function (db, request) {
|
||||||
const id = request.params.id,
|
let id = request.params.id;
|
||||||
[attrs] = JSON.parse(request.requestBody).tags,
|
let [attrs] = JSON.parse(request.requestBody).tags;
|
||||||
record = db.tags.update(id, attrs);
|
let record = db.tags.update(id, attrs);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tag: record
|
tag: record
|
||||||
@ -158,6 +228,22 @@ export default function () {
|
|||||||
|
|
||||||
/* Users ---------------------------------------------------------------- */
|
/* Users ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
this.post('/users/', function (db, request) {
|
||||||
|
let [attrs] = JSON.parse(request.requestBody).users;
|
||||||
|
let user;
|
||||||
|
|
||||||
|
if (!isBlank(attrs.email)) {
|
||||||
|
attrs.slug = attrs.email.split('@')[0].dasherize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: this does not use the user factory to fill in blank fields
|
||||||
|
user = db.users.insert(attrs);
|
||||||
|
|
||||||
|
return {
|
||||||
|
users: [user]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// /users/me = Always return the user with ID=1
|
// /users/me = Always return the user with ID=1
|
||||||
this.get('/users/me', function (db) {
|
this.get('/users/me', function (db) {
|
||||||
return {
|
return {
|
||||||
|
42
ghost/admin/app/mirage/fixtures/roles.js
Normal file
42
ghost/admin/app/mirage/fixtures/roles.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
uuid: 'b2576c4e-fa4e-41d4-8236-ced75f735222',
|
||||||
|
name: 'Administrator',
|
||||||
|
description: 'Administrators',
|
||||||
|
created_at: '2015-11-13T16:01:29.131Z',
|
||||||
|
created_by: 1,
|
||||||
|
updated_at: '2015-11-13T16:01:29.131Z',
|
||||||
|
updated_by: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
uuid: '6ee03efb-322e-4f6e-9c91-bc228b5eec6b',
|
||||||
|
name: 'Editor',
|
||||||
|
description: 'Editors',
|
||||||
|
created_at: '2015-11-13T16:01:29.131Z',
|
||||||
|
created_by: 1,
|
||||||
|
updated_at: '2015-11-13T16:01:29.131Z',
|
||||||
|
updated_by: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
uuid: 'de481b62-63f8-42c7-b5b9-6c5f5a877f53',
|
||||||
|
name: 'Author',
|
||||||
|
description: 'Authors',
|
||||||
|
created_at: '2015-11-13T16:01:29.131Z',
|
||||||
|
created_by: 1,
|
||||||
|
updated_at: '2015-11-13T16:01:29.131Z',
|
||||||
|
updated_by: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
uuid: 'ac8cbaf6-e6be-4129-b0fb-ec9ddfa61056',
|
||||||
|
name: 'Owner',
|
||||||
|
description: 'Blog Owner',
|
||||||
|
created_at: '2015-11-13T16:01:29.132Z',
|
||||||
|
created_by: 1,
|
||||||
|
updated_at: '2015-11-13T16:01:29.132Z',
|
||||||
|
updated_by: 1
|
||||||
|
}
|
||||||
|
];
|
@ -12,12 +12,14 @@ var DownloadCountPoller = Ember.Object.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
poll: function () {
|
poll: function () {
|
||||||
var interval = 2000,
|
var interval = Ember.testing ? 20 : 2000,
|
||||||
runId;
|
runId;
|
||||||
|
|
||||||
runId = Ember.run.later(this, function () {
|
runId = Ember.run.later(this, function () {
|
||||||
this.downloadCounter();
|
this.downloadCounter();
|
||||||
this.poll();
|
if (!Ember.testing) {
|
||||||
|
this.poll();
|
||||||
|
}
|
||||||
}, interval);
|
}, interval);
|
||||||
|
|
||||||
this.set('runId', runId);
|
this.set('runId', runId);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"fastclick": "1.0.6",
|
"fastclick": "1.0.6",
|
||||||
"google-caja": "5669.0.0",
|
"google-caja": "5669.0.0",
|
||||||
"jquery": "2.1.4",
|
"jquery": "2.1.4",
|
||||||
|
"jquery-deparam": "~0.5.0",
|
||||||
"jquery-file-upload": "9.5.6",
|
"jquery-file-upload": "9.5.6",
|
||||||
"jquery-hammerjs": "1.0.1",
|
"jquery-hammerjs": "1.0.1",
|
||||||
"jquery-ui": "1.11.4",
|
"jquery-ui": "1.11.4",
|
||||||
|
@ -70,6 +70,7 @@ module.exports = function (defaults) {
|
|||||||
|
|
||||||
if (app.env === 'test') {
|
if (app.env === 'test') {
|
||||||
app.import('bower_components/jquery.simulate.drag-sortable/jquery.simulate.drag-sortable.js');
|
app.import('bower_components/jquery.simulate.drag-sortable/jquery.simulate.drag-sortable.js');
|
||||||
|
app.import('bower_components/jquery-deparam/jquery-deparam.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'dem Styles
|
// 'dem Styles
|
||||||
|
168
ghost/admin/tests/acceptance/settings/setup-test.js
Normal file
168
ghost/admin/tests/acceptance/settings/setup-test.js
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/* jshint expr:true */
|
||||||
|
import {
|
||||||
|
describe,
|
||||||
|
it,
|
||||||
|
beforeEach,
|
||||||
|
afterEach
|
||||||
|
} from 'mocha';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import Ember from 'ember';
|
||||||
|
import startApp from '../../helpers/start-app';
|
||||||
|
import { invalidateSession, authenticateSession } from 'ghost/tests/helpers/ember-simple-auth';
|
||||||
|
|
||||||
|
const {run} = Ember;
|
||||||
|
|
||||||
|
describe('Acceptance: Setup', function () {
|
||||||
|
let application;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
application = startApp();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
run(application, 'destroy');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('redirects if already authenticated', function () {
|
||||||
|
const role = server.create('role', {name: 'Author'}),
|
||||||
|
user = server.create('user', {roles: [role], slug: 'test-user'});
|
||||||
|
|
||||||
|
authenticateSession(application);
|
||||||
|
|
||||||
|
visit('/setup/one');
|
||||||
|
andThen(() => {
|
||||||
|
expect(currentURL()).to.equal('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
visit('/setup/two');
|
||||||
|
andThen(() => {
|
||||||
|
expect(currentURL()).to.equal('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
visit('/setup/three');
|
||||||
|
andThen(() => {
|
||||||
|
expect(currentURL()).to.equal('/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('redirects to signin if already set up', function () {
|
||||||
|
// mimick an already setup blog
|
||||||
|
server.get('/authentication/setup/', function () {
|
||||||
|
return {
|
||||||
|
setup: [
|
||||||
|
{status: true}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
invalidateSession(application);
|
||||||
|
|
||||||
|
visit('/setup');
|
||||||
|
andThen(() => {
|
||||||
|
expect(currentURL()).to.equal('/signin');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has a successful happy path', function () {
|
||||||
|
// mimick a new blog
|
||||||
|
server.get('/authentication/setup/', function () {
|
||||||
|
return {
|
||||||
|
setup: [
|
||||||
|
{status: false}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
invalidateSession(application);
|
||||||
|
server.loadFixtures('roles');
|
||||||
|
|
||||||
|
visit('/setup');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
// it redirects to step one
|
||||||
|
expect(currentURL(), 'url after accessing /setup')
|
||||||
|
.to.equal('/setup/one');
|
||||||
|
|
||||||
|
// it highlights first step
|
||||||
|
expect(find('.gh-flow-nav .step:first-of-type').hasClass('active'))
|
||||||
|
.to.be.true;
|
||||||
|
expect(find('.gh-flow-nav .step:nth-of-type(2)').hasClass('active'))
|
||||||
|
.to.be.false;
|
||||||
|
expect(find('.gh-flow-nav .step:nth-of-type(3)').hasClass('active'))
|
||||||
|
.to.be.false;
|
||||||
|
|
||||||
|
// it displays download count (count increments for each ajax call
|
||||||
|
// and polling is disabled in testing so our count should be "2" -
|
||||||
|
// 1 for first load and 1 for first poll)
|
||||||
|
expect(find('.gh-flow-content em').text()).to.equal('2');
|
||||||
|
});
|
||||||
|
|
||||||
|
click('.btn-green');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
// it transitions to step two
|
||||||
|
expect(currentURL(), 'url after clicking "Create your account"')
|
||||||
|
.to.equal('/setup/two');
|
||||||
|
|
||||||
|
// email field is focused by default
|
||||||
|
// NOTE: $('x').is(':focus') doesn't work in phantomjs CLI runner
|
||||||
|
// https://github.com/ariya/phantomjs/issues/10427
|
||||||
|
expect(find('[name="email"]').get(0) === document.activeElement, 'email field has focus')
|
||||||
|
.to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
click('.btn-green');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
// it marks fields as invalid
|
||||||
|
expect(find('.form-group.error').length, 'number of invalid fields')
|
||||||
|
.to.equal(4);
|
||||||
|
|
||||||
|
// it displays error messages
|
||||||
|
expect(find('.error .response').length, 'number of in-line validation messages')
|
||||||
|
.to.equal(4);
|
||||||
|
|
||||||
|
// it displays main error
|
||||||
|
expect(find('.main-error').length, 'main error is displayed')
|
||||||
|
.to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// enter valid details and submit
|
||||||
|
fillIn('[name="email"]', 'test@example.com');
|
||||||
|
fillIn('[name="name"]', 'Test User');
|
||||||
|
fillIn('[name="password"]', 'password');
|
||||||
|
fillIn('[name="blog-title"]', 'Blog Title');
|
||||||
|
click('.btn-green');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
// it transitions to step 3
|
||||||
|
expect(currentURL(), 'url after submitting step two')
|
||||||
|
.to.equal('/setup/three');
|
||||||
|
|
||||||
|
// submit button is "disabled"
|
||||||
|
expect(find('button[type="submit"]').hasClass('btn-green'), 'invite button with no emails is white')
|
||||||
|
.to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// fill in a valid email
|
||||||
|
fillIn('[name="users"]', 'new-user@example.com');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
// submit button is "enabled"
|
||||||
|
expect(find('button[type="submit"]').hasClass('btn-green'), 'invite button is green with valid email address')
|
||||||
|
.to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// submit the invite form
|
||||||
|
click('button[type="submit"]');
|
||||||
|
|
||||||
|
andThen(() => {
|
||||||
|
// it redirects to the home / "content" screen
|
||||||
|
expect(currentURL(), 'url after submitting invites')
|
||||||
|
.to.equal('/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles server validation errors in step 2');
|
||||||
|
it('handles server validation errors in step 3');
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user