0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-25 02:31:59 -05:00

Merge pull request #3280 from jaswilli/issue-3145

Prevent loading setup screen if already setup
This commit is contained in:
Hannah Wolfe 2014-07-16 19:36:51 +01:00
commit 5f5b767b35
9 changed files with 78 additions and 31 deletions

View file

@ -449,7 +449,7 @@ var path = require('path'),
// This really ought to be refactored into a separate grunt task module // This really ought to be refactored into a separate grunt task module
grunt.registerTask('spawnCasperJS', function (target) { grunt.registerTask('spawnCasperJS', function (target) {
target = _.contains(['client', 'frontend'], target) ? target + '/' : undefined; target = _.contains(['client', 'frontend', 'setup'], target) ? target + '/' : undefined;
var done = this.async(), var done = this.async(),
options = ['host', 'noPort', 'port', 'email', 'password'], options = ['host', 'noPort', 'port', 'email', 'password'],
@ -550,6 +550,22 @@ var path = require('path'),
}); });
}); });
// #### Reset Database to "New" state *(Utility Task)*
// Drops all database tables and then runs the migration process to put the database
// in a "new" state.
grunt.registerTask('cleanDatabase', function () {
var done = this.async(),
migration = require('./core/server/data/migration');
migration.reset().then(function () {
return migration.init();
}).then(function () {
done();
}).catch(function (err) {
grunt.fail.fatal(err.stack);
});
});
// ### Validate // ### Validate
// **Main testing task** // **Main testing task**
// //
@ -637,6 +653,16 @@ var path = require('path'),
grunt.registerTask('test-routes', 'Run functional route tests (mocha)', grunt.registerTask('test-routes', 'Run functional route tests (mocha)',
['clean:test', 'setTestEnv', 'loadConfig', 'mochacli:routes']); ['clean:test', 'setTestEnv', 'loadConfig', 'mochacli:routes']);
// ### Functional tests for the setup process
// `grunt test-functional-setup will run just the functional tests for the setup page.
//
// Setup only works with a brand new database, so it needs to run isolated from the rest of
// the functional tests.
grunt.registerTask('test-functional-setup', 'Run functional tests for setup',
['clean:test', 'setTestEnv', 'loadConfig', 'cleanDatabase', 'express:test',
'spawnCasperJS:setup', 'express:test:stop']
);
// ### Functional tests *(sub task)* // ### Functional tests *(sub task)*
// `grunt test-functional` will run just the functional tests // `grunt test-functional` will run just the functional tests
// //
@ -656,7 +682,8 @@ var path = require('path'),
// The purpose of the functional tests is to ensure that Ghost is working as is expected from a user perspective // The purpose of the functional tests is to ensure that Ghost is working as is expected from a user perspective
// including buttons and other important interactions in the admin UI. // including buttons and other important interactions in the admin UI.
grunt.registerTask('test-functional', 'Run functional interface tests (CasperJS)', grunt.registerTask('test-functional', 'Run functional interface tests (CasperJS)',
['clean:test', 'setTestEnv', 'loadConfig', 'express:test', 'spawnCasperJS', 'express:test:stop'] ['clean:test', 'setTestEnv', 'loadConfig', 'cleanDatabase', 'express:test', 'spawnCasperJS', 'express:test:stop',
'test-functional-setup']
); );
// ### Coverage // ### Coverage

View file

@ -3,10 +3,29 @@ import loadingIndicator from 'ghost/mixins/loading-indicator';
var SetupRoute = Ember.Route.extend(styleBody, loadingIndicator, { var SetupRoute = Ember.Route.extend(styleBody, loadingIndicator, {
classNames: ['ghost-setup'], classNames: ['ghost-setup'],
// use the beforeModel hook to check to see whether or not setup has been
// previously completed. If it has, stop the transition into the setup page.
beforeModel: function () { beforeModel: function () {
var self = this;
// If user is logged in, setup has already been completed.
if (this.get('session').isAuthenticated) { if (this.get('session').isAuthenticated) {
this.transitionTo(Ember.SimpleAuth.routeAfterAuthentication); this.transitionTo(Ember.SimpleAuth.routeAfterAuthentication);
return;
} }
// If user is not logged in, check the state of the setup process via the API
return ic.ajax.request(this.get('ghostPaths.url').api('authentication/setup'), {
type: 'GET'
}).then(function (result) {
var setup = result.setup[0].status;
if (setup) {
return self.transitionTo('signin');
}
});
} }
}); });

View file

@ -16,13 +16,13 @@
<h3>Stack Trace</h3> <h3>Stack Trace</h3>
<p><strong>{{message}}</strong></p> <p><strong>{{message}}</strong></p>
<ul class="error-stack-list"> <ul class="error-stack-list">
{{#foreach stack}} {{#each stack}}
<li> <li>
at at
{{#if function}}<em class="error-stack-function">{{function}}</em>{{/if}} {{#if function}}<em class="error-stack-function">{{function}}</em>{{/if}}
<span class="error-stack-file">({{at}})</span> <span class="error-stack-file">({{at}})</span>
</li> </li>
{{/foreach}} {{/each}}
</ul> </ul>
</section> </section>
{{/if}} {{/if}}

View file

@ -3,13 +3,13 @@ var SetupValidator = Ember.Object.create({
var data = model.getProperties('blogTitle', 'name', 'email', 'password'), var data = model.getProperties('blogTitle', 'name', 'email', 'password'),
validationErrors = []; validationErrors = [];
if (!validator.isLength(data.blogTitle || '', 1)) { if (!validator.isLength(data.blogTitle, 1)) {
validationErrors.push({ validationErrors.push({
message: 'Please enter a blog title.' message: 'Please enter a blog title.'
}); });
} }
if (!validator.isLength(data.name || '', 1)) { if (!validator.isLength(data.name, 1)) {
validationErrors.push({ validationErrors.push({
message: 'Please enter a name.' message: 'Please enter a name.'
}); });
@ -21,9 +21,9 @@ var SetupValidator = Ember.Object.create({
}); });
} }
if (!validator.isLength(data.password || '', 1)) { if (!validator.isLength(data.password, 8)) {
validationErrors.push({ validationErrors.push({
message: 'Please enter a password.' message: 'Password must be at least 8 characters long.'
}); });
} }

View file

@ -3,7 +3,7 @@ var SignupValidator = Ember.Object.create({
var data = model.getProperties('name', 'email', 'password'), var data = model.getProperties('name', 'email', 'password'),
validationErrors = []; validationErrors = [];
if (!validator.isLength(data.name || '', 1)) { if (!validator.isLength(data.name, 1)) {
validationErrors.push({ validationErrors.push({
message: 'Please enter a name.' message: 'Please enter a name.'
}); });
@ -15,9 +15,9 @@ var SignupValidator = Ember.Object.create({
}); });
} }
if (!validator.isLength(data.password || '', 1)) { if (!validator.isLength(data.password, 8)) {
validationErrors.push({ validationErrors.push({
message: 'Please enter a password.' message: 'Password must be at least 8 characters long.'
}); });
} }

View file

@ -41,13 +41,13 @@
<h3>Stack Trace</h3> <h3>Stack Trace</h3>
<p><strong>{{message}}</strong></p> <p><strong>{{message}}</strong></p>
<ul class="error-stack-list"> <ul class="error-stack-list">
{{#foreach stack}} {{#each stack}}
<li> <li>
at at
{{#if function}}<em class="error-stack-function">{{function}}</em>{{/if}} {{#if function}}<em class="error-stack-function">{{function}}</em>{{/if}}
<span class="error-stack-file">({{at}})</span> <span class="error-stack-file">({{at}})</span>
</li> </li>
{{/foreach}} {{/each}}
</ul> </ul>
</section> </section>
{{/if}} {{/if}}

View file

@ -91,7 +91,7 @@ screens = {
'signin-authenticated': { 'signin-authenticated': {
url: 'ghost/signin/', url: 'ghost/signin/',
//signin with authenticated user redirects to posts //signin with authenticated user redirects to posts
selector: '#main-menu .content.active' selector: '#main-menu .content .active'
}, },
'signout': { 'signout': {
url: 'ghost/signout/', url: 'ghost/signout/',
@ -109,7 +109,7 @@ screens = {
}, },
'setup-authenticated': { 'setup-authenticated': {
url: 'ghost/setup/', url: 'ghost/setup/',
selector: '#main-menu .content.active' selector: '#main-menu .content a.active'
} }
}; };
@ -386,9 +386,9 @@ CasperTest.Routines = (function () {
var errorText = casper.evaluate(function () { var errorText = casper.evaluate(function () {
return document.querySelector('.notification-error').innerText; return document.querySelector('.notification-error').innerText;
}); });
casper.echoConcise('It appears as though a user is already registered. Error text: ' + errorText); casper.echoConcise('Setup failed. Error text: ' + errorText);
}, function onTimeout() { }, function onTimeout() {
casper.echoConcise('It appears as though a user was not already registered.'); casper.echoConcise('Setup completed.');
}, 2000); }, 2000);
casper.captureScreenshot('setting_up3.png'); casper.captureScreenshot('setting_up3.png');

View file

@ -3,7 +3,6 @@
/*globals CasperTest, casper */ /*globals CasperTest, casper */
CasperTest.begin('Ghost signout works correctly', 3, function suite(test) { CasperTest.begin('Ghost signout works correctly', 3, function suite(test) {
CasperTest.Routines.setup.run(test);
CasperTest.Routines.signout.run(test); CasperTest.Routines.signout.run(test);
CasperTest.Routines.signin.run(test); CasperTest.Routines.signin.run(test);
@ -31,4 +30,4 @@ CasperTest.begin('Ghost signout works correctly', 3, function suite(test) {
casper.captureScreenshot('user-menu-logout-clicked.png'); casper.captureScreenshot('user-menu-logout-clicked.png');
}, true); }, true);

View file

@ -3,33 +3,35 @@
/*global CasperTest, casper, email */ /*global CasperTest, casper, email */
CasperTest.begin('Ghost setup fails properly', 5, function suite(test) { CasperTest.begin('Ghost setup fails properly', 6, function suite(test) {
casper.thenOpenAndWaitForPageLoad('setup', function then() { casper.thenOpenAndWaitForPageLoad('setup', function then() {
test.assertUrlMatch(/ghost\/setup\/$/, 'Landed on the correct URL'); test.assertUrlMatch(/ghost\/setup\/$/, 'Landed on the correct URL');
}); });
casper.then(function setupWithShortPassword() { casper.then(function setupWithShortPassword() {
casper.fillAndAdd('#setup', {email: email, password: 'test'}); casper.fillAndAdd('#setup', { 'blog-title': 'ghost', name: 'slimer', email: email, password: 'short' });
}); });
// should now throw a short password error // should now throw a short password error
casper.waitForSelector('.notification-error', function onSuccess() { casper.waitForSelector('.notification-error', function onSuccess() {
test.assert(true, 'Got error notification'); test.assert(true, 'Got error notification');
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]'); test.assertSelectorHasText('.notification-error', 'Password must be at least 8 characters long');
}, function onTimeout() { }, function onTimeout() {
test.assert(false, 'No error notification :('); test.assert(false, 'No error notification :(');
}); });
casper.then(function setupWithLongPassword() { casper.then(function setupWithLongPassword() {
casper.fillAndAdd('#setup', {email: email, password: 'testing1234'}); casper.fillAndAdd('#setup', { 'blog-title': 'ghost', name: 'slimer', email: email, password: password });
}); });
// should now throw a 1 user only error casper.wait(2000);
casper.waitForSelector('.notification-error', function onSuccess() {
test.assert(true, 'Got error notification'); casper.waitForResource(/\d+/, function testForDashboard() {
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]'); test.assertUrlMatch(/ghost\/\d+\/$/, 'Landed on the correct URL');
}, function onTimeout() { test.assertExists('#global-header', 'Global admin header is present');
test.assert(false, 'No error notification :('); test.assertExists('.manage', 'We\'re now on content');
}, function onTimeOut() {
test.fail('Failed to signin');
}); });
}, true); }, true);
@ -39,13 +41,13 @@ CasperTest.begin('Authenticated user is redirected', 8, function suite(test) {
test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL'); test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
}); });
casper.waitForOpaque('.login-box', function then() { casper.waitForOpaque('.login-box', function then() {
this.fillAndSave('#login', user); this.fillAndSave('#login', user);
}); });
casper.wait(2000); casper.wait(2000);
casper.waitForResource(/posts/, function testForDashboard() { casper.waitForResource(/\d+/, function testForDashboard() {
test.assertUrlMatch(/ghost\/\d+\/$/, 'Landed on the correct URL'); test.assertUrlMatch(/ghost\/\d+\/$/, 'Landed on the correct URL');
test.assertExists('#global-header', 'Global admin header is present'); test.assertExists('#global-header', 'Global admin header is present');
test.assertExists('.manage', 'We\'re now on content'); test.assertExists('.manage', 'We\'re now on content');